1

我正在使用实体框架 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 的所有者为空时,不允许请求的操作。使用默认构造函数创建的 RelatedEnd 对象只能在序列化期间用作容器。

4

3 回答 3

1

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

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

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

顺便说一句:您可以model.Database.Delete()在不检查数据库是否存在的情况下使用。而DetectChanges()就在之前SaveChanges()是多余的。

于 2012-11-18T22:04:34.573 回答
0

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

无论如何,我的直觉是寻找循环引用或其他阻止对象属性在您的一个类上实例化的条件。

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

于 2012-11-18T19:14:05.327 回答
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);
    }

现在它给了一个绿色

于 2012-11-25T12:55:53.100 回答