Type 'System.ObjectDisposedException'的异常

4
我有以下的EF code first代码。它工作得很好。但是当我查看 'club2.Members' 的值时,它会出现以下错误信息:
'club2.Members' 抛出了类型为 'System.ObjectDisposedException' 的异常。
错误消息如下:
ObjectContext实例已被处理,并且不能再用于需要连接的操作。
我没有为Members属性设置值。这没关系。然而,它不应该在内部引起任何异常。
1. 有没有办法克服这个异常? 2. 解决此异常是否有助于提高性能? 3. 为什么此异常不会导致程序执行终止?
注意:在调用时,我不需要俱乐部实体中的成员数据。 即使此时没有添加成员,我仍需要消除异常;而不是使用贪婪加载来加载数据。 如何避免异常?
namespace LijosEF
{

public class Person
{
    public int PersonId { get; set; }
    public string PersonName { get; set; }
    public virtual ICollection<Club> Clubs { get; set; }
}

public class Club 
{
    public int ClubId { get; set; }
    public string ClubName { get; set; }
    public virtual ICollection<Person> Members { get; set; }

}




//System.Data.Entity.DbContext is from EntityFramework.dll
public class NerdDinners : System.Data.Entity.DbContext
{

    public NerdDinners(string connString): base(connString)
    { 

    }

    protected override void OnModelCreating(DbModelBuilder modelbuilder)
    {
         //Fluent API - Plural Removal
        modelbuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }

    public DbSet<Person> Persons { get; set; }
    public DbSet<Club> Clubs { get; set; }



}
}




    static void Main(string[] args)
    {
        Database.SetInitializer<NerdDinners>(new MyInitializer());

        CreateClubs();
        CreatePersons();

    }

    public static void CreateClubs()
    {

        string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
        using (var db = new NerdDinners(connectionstring))
        {

            Club club1 = new Club();
            club1.ClubName = "club1";

            Club club2 = new Club();
            club2.ClubName = "club2";

            Club club3 = new Club();
            club3.ClubName = "club3";

            db.Clubs.Add(club1);
            db.Clubs.Add(club2);
            db.Clubs.Add(club3);

            int recordsAffected = db.SaveChanges();


        }
    }

    public static Club GetClubs(string clubName)
    {
        string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
        using (var db = new NerdDinners(connectionstring))
        {

            var query = db.Clubs.SingleOrDefault(p => p.ClubName == clubName);
            return query;
        }
    }

    public static void CreatePersons()
    {
        string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
        using (var db = new NerdDinners(connectionstring))
        {

            Club club1 = GetClubs("club1");
            Club club2 = GetClubs("club2");
            Club club3 = GetClubs("club3");

             //More code to be added (using db) to add person to context and save
        }
    }

我刚才看了你的代码,为什么在CheckValues中又创建了另一个db实例? - Amiram Korach
@AmiramKorach 我有另一种方法 - CreatePersons。我将不得不在那里使用新的上下文。我正在使用每个请求的上下文方法。人员需要了解俱乐部的情况。 - LCJ
这段代码没有意义。在CreatePersons中根本没有使用db变量。每个GetClubs调用都使用自己的db变量。 - Amiram Korach
@AmiramKorach。CreatePersosns方法中将添加更多代码(使用db)以将人员添加到上下文并保存。 - LCJ
好的。请确保不要在不同上下文之间连接实体。 - Amiram Korach
请尝试添加以下代码:var query = db.Clubs.SingleOrDefault(p => p.ClubName == clubName); /* 尝试这样写...*/ if (query.Members == null) {} return query;看看会发生什么... - Jitka Darbie Hübnerová
2个回答

9
您之所以会出现这个错误,是因为您在执行查询后处置了dbcontext。 如果您想使用“members”中的数据,请使用查询加载它: http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx 如果您不需要延迟加载,这意味着只有在查询中加载的数据会被加载(这将消除异常),请设置LazyLoadingEnabled = false。 请参阅此处: Disable lazy loading by default in Entity Framework 4

我在调用时不需要俱乐部实体中的成员数据。即使在那个时候俱乐部中没有添加成员,我也不需要它。我所需要做的就是摆脱异常,而不是加载数据。如何避免这个异常? - LCJ

1

方法一

在当前情境下,无需使用以下方法。这只是一个选择。

GetClubs("club1");

方法2

附加实体解决了问题:

            Club club1 = GetClubs("club1");
            Club club2 = GetClubs("club2");
            Club club3 = GetClubs("club3");

            ((IObjectContextAdapter)db).ObjectContext.Attach((IEntityWithKey)club1);
            ((IObjectContextAdapter)db).ObjectContext.Attach((IEntityWithKey)club2);
            ((IObjectContextAdapter)db).ObjectContext.Attach((IEntityWithKey)club3);


            var test = club2.Members;

我不应该尝试引用Club类的club2.Members(成员),因为这对于创建Person对象并不需要。

Members是Club类中的相关数据。由于它是虚拟的,它将进行延迟加载。

在不同的情况下,如果我必须从不同的上下文中检索Members对象(即相关数据),我应该依赖急切加载(在提供Club对象的地方)。

请参考以下内容:

  1. Entity Framework:多对多关系中的重复记录

  2. System.ObjectDisposedException:ObjectContext 实例已被处理并且不能再用于需要连接的操作

  3. ObjectContext 实例已被处理并且不能再用于需要连接的操作

  4. 绑定时 ObjectContext 实例已被处理


@AmiramKorach 你觉得这种方法怎么样? - LCJ
1
坚持Amiram的建议。这只有在您将实体重新附加到新上下文时才有效。我认为在您的情况下,您想要使用Include进行急切加载。每次访问导航属性时都打开新上下文不是一个好主意。请记住,因为您将导航属性标记为虚拟的,EF将返回一个动态代理,当上下文被处理时它将无法工作。在关闭上下文之前返回所需的所有数据将解决此问题。 - JaySilk84
我认为这很危险。正如我在上面评论的那样,我认为根本没有必要在CheckValues中打开新的上下文。此外,我不会尝试将实体附加到多个上下文中。我不确定你是否会因此而得到异常。 - Amiram Korach
@JaySilk84 我认为,急切加载是用于检索相关数据的。在我的情况下,我不是在检索相关数据 - 我只是设置相关数据(俱乐部是人的相关数据)。我不认为需要急切加载。你觉得呢? - LCJ
1
@Lijo 如果你不需要数据,那就不要访问导航属性。在你上面的情况中,只有当你尝试展开“Members”属性时,调试器才会抛出异常。如果你从未访问该属性,则不会在运行时抛出该异常。如果你永远不需要查看俱乐部中的所有成员(Club.Members),而只需要知道一个人属于哪些俱乐部(Person.Clubs),那么就将 Club 上的 Members 导航属性移除即可。你不需要映射模型中的所有属性或关系。 - JaySilk84
@JaySilk84 谢谢。那很有道理。请看我的更新答案。另外,我还有一个EF问题http://stackoverflow.com/questions/11632951/primary-key-violation-inheritance-using-ef-code-first。 - LCJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接