2016-07-15 75 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

正確的配置對於解決方案的運行至關重要。最初我沒有包含配置,並且正在獲得與您在帖子中解釋的行爲完全相同的行爲。 –