EF6.1不以多对多关系加载其他实体

时间:2014-11-25 15:09:48

标签: c# entity-framework many-to-many

我有两个实体类,它们具有多对多关系类,未被建模为弱实体:

public class Foo 
{
    public Guid Id { get; private set; }
    public ICollection<Baz> Bazs { get; private set; }
}

public class Bar 
{
    public long Id { get; private set; }
}

public class Baz 
{
    public Guid Id { get; private set; }
    public Foo Foo { get; private set; }
    public Bar Bar { get; private set; }
    // other things
}

我的EntityTypeConfigurations就像这样构建:

public class FooConfiguration : EntityTypeConfiguration<Foo> 
{
    HasMany(f => f.Bazs).WithRequired(b => b.Foo).Map(c => c.ToTable("FooBars"));
}

public class BarConfiguration : EntityTypeConfiguration<Bar> 
{
    //no navigation mapping
}

public class BazConfiguration : EntityTypeConfiguration<Baz>
{
    HasRequired(b => b.Foo).WithMany(f => f.Bazs);
    HasRequired(b => b.Bar).WithMany();
}

我遇到的问题是,当我加载Foo时,Bar关系的Baz方面无法加载。我已经更改了Baz上的属性以获得支持字段并在setter上设置断点,并且Foo的setter被调用,但Bar的setter却没有。我还尝试在Bar虚拟上创建Baz属性,看看是否出于某种原因需要急切加载的情况。这种用法的一个例子:

var foo = Set<Foo>.Single(f => f.Id == Id);
var barIds = foo.Bazs.Select(b => b.Bar.Id).ToList(); 
// the projection lambda throws because b.Bar is null

但是,如果我明确加载Bar,他们会填充:

var bars = Set<Bar>().ToList();
var foo = Set<Foo>().Single(f => f.Id == Id);
var barIds = foo.Bazs.Select(b => b.Bar.Id).ToList(); 
// barIds now contains the correct IDs for the associated Bars

我的问题是:

  1. 加载Bar之前加载Foo的解决方法是填充实体的唯一方法吗?
  2. 如果没有,我错过了什么?
  3. 其他信息

    我已尝试直接在ICollection<Bar>上使用Foo,该Foo用于加载Bar - &gt; Baz关系,但因为SaveChanges()是不是弱实体,此设置在{{1}}上失败。

    我尝试过两种方式映射集合,但是that's apparently not possible either

2 个答案:

答案 0 :(得分:2)

在你的例子中“工作”EF只是填充属性,因为它在它的本地缓存中有它们,但是这不是你需要的方法。

您需要在查询中明确包含Bazs.Bar,如下所示,它们会急切加载它们。

var foo = Set<Foo>().Include("Bazs.Bar").Single(f => f.Id == Id);

或者,如果您将导航属性声明为virtual,那么这将启用延迟加载。

public class Foo 
{
    public Guid Id { get; private set; }
    public virtual ICollection<Baz> Bazs { get; private set; }
}

public class Baz 
{
    public Guid Id { get; private set; }
    public virtual Foo Foo { get; private set; }
    public virtual Bar Bar { get; private set; }
    // other things
}

答案 1 :(得分:0)

值得注意的一件事(虽然不必修正 OP,但是因为代码示例是Foo-Bared,所以可能会过于简化-无论如何,已经有4年了,所以我确定OP不再关心了。

EF要求实体类至少具有受保护的无参数构造函数。 如果您的参数构造函数是私有的,则将加载该实体,但是导航属性的延迟加载将不起作用-不管它是否是虚拟的。

必须显式加载导航属性(例如,使用Include)。

嘘:

public class Foo 
{
    //private constructor won't lazy-load navigation properties (virtual or not).
    //change to protected 
    private Foo(){}  
    public Foo(string name)
    { 
        this.Name = name; 
    }
    public string Name {get;set;}
    public Guid Id { get; private set; }
    public virtual ICollection<Baz> Bazs { get; private set; }
}