延迟加载EntityCollection

时间:2012-11-18 15:39:39

标签: entity-framework

我正在使用实体框架5。 我正在尝试延迟加载实体集合,我将模型剥离到裸骨以获得一个简单的可运行样本。

这是我的模特:

public class A
{

    public int Id { get; set; }

    public EntityCollection<B> Bs
    {
        get { return bs; }
        set { bs = value; }
    }
    private EntityCollection<B> bs;

    public A()
    {
        bs = new EntityCollection<B>();
    }
}

public class B
{
    public int Id { get; set; }
    public A A { get; set; }
}

public class DbModel : DbContext
{
    public DbSet<A> As { get; set; }
    public DbSet<B> Bs { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<A>()
                    .HasKey( t => t.Id )
                    .HasMany(a => a.Bs)
                    .WithRequired(b => b.A);
        modelBuilder.Entity<A>()
                    .Property(t => t.Id)
                    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        modelBuilder.Entity<B>()
                    .HasKey(b => b.Id)
                    .HasRequired(b => b.A);
        modelBuilder.Entity<B>()
                    .Property( t => t.Id )
                    .HasDatabaseGeneratedOption( DatabaseGeneratedOption.Identity );
    }

这是证明我的问题的测试:

   [TestInitialize]
    public void Initialize()
    {
        model = new DbModel();
        model.Configuration.ProxyCreationEnabled = false;

        if (model.Database.Exists()) model.Database.Delete();

        model.Database.Create();
        A a = model.As.Create();
        model.As.Add(a);
        B b = model.Bs.Create();
        a.Bs.Add(b);

        model.ChangeTracker.DetectChanges();
        model.SaveChanges();
    }

   [TestMethod]
    public void TestMethod1()
    {
        // arrange
        DbModel tModel = new DbModel();
        A a = tModel.As.First();

        // act
        a.Bs.Load();
    }

结果如下:

测试方法TestProject1.UnitTest1.TestMethod1抛出异常:

  

System.InvalidOperationException:不允许请求的操作   当此RelatedEnd的所有者为null时。 RelatedEnd对象   使用默认构造函数创建的应仅用作a   序列化期间的容器。

3 个答案:

答案 0 :(得分:1)

EntitySet是linq-to-sql API的一部分。这并没有解释这个特殊的例外情况,但与DbContext的合作不太顺利也不足为奇。当您使用DbContext API时,通常将1:n导航属性定义为ICollection之类的接口:

public virtual ICollection<B> Bs { get; set; }

virtual为延迟加载启用代理创建)

暂且不说:您可以使用model.Database.Delete()而无需检查数据库是否存在。 <{1}}之前的DetectChanges()是多余的。

答案 1 :(得分:0)

有点费解,这段代码。你真的想要一个包含对A类的引用的类(B),而A类又有B的集合吗?也许它只是混淆的名字,但我无法想象这样的对象模型的场景。

在任何情况下,我的直觉都是寻找循环引用或其他条件阻止在其中一个类上实例化对象属性。

此外,您正在使用a.Bs.Load()在测试方法中使用Eager加载。设置ProxyCreationEnabled = false时禁用延迟加载。

答案 2 :(得分:0)

事实证明我使用的是来自ADO家族不同范例的课程。 正如Gert Arnold所指出的,EF不能与EntityCollection一起使用,它使用了一个简单的列表来进行关联集合。

public class A
{

    public int Id { get; set; }

    public List<B> Bs
    {
        get { return bs; }
        set { bs = value; }
    }
    private List<B> bs = new List<B>();
}

由于我不想要代理,因此对象没有模型的“知识”。因此,模型本身必须用于加载实体的关联。 对于此示例,我将以下方法添加到模型中:

public class DbModel : DbContext
{
    public DbSet<A> As { get; set; }
    public DbSet<B> Bs { get; set; }

//…

    public A LoadAWithAssociations(A targetA)
    {
        return As.Include("Bs").First(a => a.Id.Equals(targetA.Id));
    }
}

我调整了测试以使用新方法

  [TestMethod]
    public void TestMethod1()
    {
        // arrange
        DbModel tModel = new DbModel();
        A a = tModel.As.First();

        // act
        A result =  tModel.LoadAWithAssociations(a);

        // assert 
        Assert.IsNotNull(result);
        Assert.IsTrue(result.Bs.Count > 0);
    }

现在给出绿色