2016-07-15 36 views
3

我宣布这样一个实体(实际的类显然也有一个ID属性,映射完成等,但它不是问题,所以我在这里省略吧):不实体框架是否支持受保护的导航属性?

public class Parent 
{ 
    public virtual ICollection<Child> Children {get; set;} 
} 

该作品完美:

public class Consumer 
{ 
    void DoBusiness() 
    { 
     using (var ctx = new MyDbContext()) 
     { 
      var entity = ctx.Parents.Find(keyOfParent); 
      // This is as expected: entity.Children refers to a collection which 
      // Entity Framework has assigned, a collection which supports lazy loading. 
     } 
    } 
} 

现在我改变了孩子们收集的知名度,被保护:

public class Parent 
{ 
    protected virtual ICollection<Child> Children {get; set;} 
} 

这带来了一个意想不到的结果:

public class Consumer 
{ 
    void DoBusiness() 
    { 
     using (var ctx = new MyDbContext()) 
     { 
      var entity = ctx.Parents.Find(keyOfParent); 
      // This is NOT as expected: entity.Children is null. I would expect, that it 
      // had been referring to a collection which Entity Framework would have been 
      // assigning, a collection which should support lazy loading. 
     } 
    } 
} 

此外,如果我的情况,那里的儿童保护尝试通过显式地加载孩子:

ctc.Entry(entity).Collection(x => x.Children) 

然后我得到这个异常:

属性“ “父母”类型的“孩子”不是导航属性。引用和收集方法只能与导航属性一起使用。使用Property或ComplexProperty方法。

因此:为了拥有使用实体框架的受保护导航属性,我应该做些什么?

+3

为什么你想在地球上做到这一点? EF中的“实体”不过是数据库表,记录和关系的对象表示。他们不应该包含业务逻辑。因此,他们和他们的成员应该是可见的,以便用于查询。示例代码'ctc.Entry(entity).Collection(x => x.Children)'只能在与这些原则相违背的Parent类中运行。 –

+0

由于具体属性(与示例中的Children相对应)仅通过反射来使用,因此您提供的有关查询的基本考虑事项不适用。关于你的编码评论:显然,是的,但它强调实体框架在被保护之后不会将该属性视为导航属性。你也有一些贡献信息吗? –

+0

如果该属性标记为'protected',框架将如何使用该属性并加载它?它不能“看到”它;只有儿童班才可以。 –

回答

1

这是我如何使它工作。

public class Parent 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    internal ICollection<Child> children; 
    protected virtual ICollection<Child> Children { get { return children; } set { children = value; } } 
    internal ICollection<Child> GetChildren() => Children; 
    internal static Expression<Func<Parent, ICollection<Child>>> ChildrenSelector => p => p.Children; 
} 

public class Child 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    internal Parent parent; 
    protected virtual Parent Parent { get { return parent; } set { parent = value; } } 
    internal Parent GetParent() => Parent; 
    internal static Expression<Func<Child, Parent>> ParentSelector => c => c.Parent; 
} 

public class MyDbContext : DbContext 
{ 
    public DbSet<Parent> Parents { get; set; } 
    public DbSet<Child> Children { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Parent>() 
      .HasMany(Parent.ChildrenSelector) 
      .WithRequired(Child.ParentSelector) 
      .Map(a => a.MapKey("ParentId")); 

     base.OnModelCreating(modelBuilder); 
    } 
} 

使用显式字段是不是必需的 - 我把他们为了能够看什么在那里,你可以继续使用自动属性。

重要的部分是提供属性访问器表达式并将它们与Fluent API配置结合使用。没有明确的配置,你会得到你所描述的行为。有了它,一切正常。

举例来说,延迟加载:

var parent = ctx.Parents.Find(keyOfParent); 
var children = parent.GetChildren(); 

或显式加载:

var parent = ctx.Parents.Find(keyOfParent); 
db.Entry(parent).Collection("Children").Load(); 
var children = parent.children; 

UPDATE:相当怪异,如果我们用替换配置代码

modelBuilder.Entity<Parent>() 
    .HasMany(Parent.ChildrenSelector) 
    .WithRequired(Child.ParentSelector) 
    .Map(a => a.MapKey("ParentId")); 

完全等同于定义

modelBuilder.Entity<Child>() 
    .HasRequired(Child.ParentSelector) 
    .WithMany(Parent.ChildrenSelector) 
    .Map(a => a.MapKey("ParentId")); 

数据库表和FKs是相同的,但加载不起作用!所以无论是工作解决方案是不小心碰到了后门,还是EF中都存在一个错误。在这两种情况下,该功能对我来说似乎都有问题,我只是简单地使用public访问器以避免意外。

+0

非常感谢伊万。这真的是非常好的建设性的你!你不能改变模型的定义位,即用替换你:modelBuilder.Entity ().HasRequired(Child.ParentSelector).WithMany(Parent.ChildrenSelector).MAP(A => a.MapKey(“的ParentId “));并看看代理的东西是否仍然有效?这两种方法不应该相互矛盾吗?实际上你有使用Map而不是HasForeignKey的原因吗? –

+0

'HasForeignKey'是当你在模型中有明确的字段。例如如果'Child'类具有'public int ParentId {get;组; }'那么你将使用'HasForeignKey(c => c.ParentId)''。如果您没有这样的显式字段并且只是为该字段指定表列名称,则会使用MapKey。这是可选的,如果你不包含它,你会默认获得“Parent_Id”。配置非常重要,并且取决于您明确包含在实体类中的字段的不同而不同。 –

+0

正确的配置对于解决方案的运行至关重要。最初我没有包含配置,并且正在获得与您在帖子中解释的行为完全相同的行为。 –