不知咱們是否思考過一個問題,在關係映射中對於導航屬性的訪問修飾符是否必定必須爲public呢?若是從未想過這個問題,那麼咱們接下來來探討這個問題。ui
在EF 6.x中咱們建立以下示例類。spa
public partial class Customer { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public ICollection<Order> Orders { get; set; } = new List<Order>(); }
public class Order : BaseEntity { public int Quantity { get; set; } public string Code { get; set; } public decimal Price { get; set; } public int CustomerId { get; set; } public Customer Customer { get; set; } }
上述咱們不顯式配置映射關係,EF和EF Core會根據約定來配置,一樣達到如咱們指望的,不管是EF 6.x仍是EF Core中經過Inlcude進行顯式加載有兩種方式,一種是基於字符串,另一種則是經過lamda表達式的方式(命名空間存在於System.Data.Entity),接下來咱們來看下:code
using (var ctx = new EfDbContext()) { ctx.Database.Log = Console.WriteLine; var customers = ctx.Customers.Include(d => d.Orders).ToList(); };
這樣是咱們一直以來最正常的操做,如前言所敘,那麼導航屬性難道必須是public嗎?接下來咱們來試試。咱們嘗試將Orders導航屬性配置成以下私有的。htm
private ICollection<Order> Orders { get; set; } = new List<Order>();
由於其爲私有,若經過lambda表達式確定是訪問受限制,那麼咱們改成經過基於字符串的方式來顯式加載,以下:blog
using (var ctx = new EfDbContext()) { ctx.Database.Log = Console.WriteLine; var customers = ctx.Customers.Include("Orders").ToList(); };
如上則拋出異常找不到Orders導航屬性,是否是到此下結論而定導航屬性必須是public呢?訪問修飾符除了public,還有protected、internal以及protected internal。經過實踐驗證若導航屬性爲private、protected訪問修飾符確定不行,若爲internal和protected internal則能夠,前提是必須顯式配置映射關係,不然也不行,以下:ci
protected internal ICollection<Order> Orders { get; set; } = new List<Order>();
HasMany(p => p.Orders).WithRequired(p => p.Customer).HasForeignKey(k => k.CustomerId);
那麼在EF Core是否也和EF 6.x同樣呢?咱們繼續來看看在EF Core中的狀況,示例類爲Blog和Post,這兩個類已經在博客文章屢次被用到,就再也不給出,咱們只關係導航屬性訪問修飾符的配置,以下:字符串
private ICollection<Post> Posts { get; set; } = new List<Post>();
using (var context = new EFCoreDbContext()) { var blogs = context.Blogs.Include("Posts").ToList(); }
此時會一樣拋出異常,只不過異常信息大意是Posts不是Blog導航屬性的一部分,對於基於字符串的Include方法,導航屬性名稱要以點分隔開,最終結果仍是是找不到Posts導航屬性,接下來咱們將訪問修飾符改成internal看看。get
internal ICollection<Post> Posts { get; set; } = new List<Post>();
using (var context = new EFCoreDbContext()) { var blogs = context.Blogs.Include(d => d.Posts).ToList(); //var blogs1 = context.Blogs.Include("Posts").ToList(); }
此時咱們再來顯式配置映射關係則好使。源碼
builder.HasMany(m => m.Posts)
.WithOne(o => o.Blog);
對於EF和EF Core中經過Include方法進行顯式加載具體實現沒有去看源碼,徹底經過實踐獲得的結論是:不管是EntityFramework仍是EntityFramework Core,在關係映射中導航屬性不必定必須是public修飾符,也能夠爲internal和protected internal,可是前提是必須顯式配置映射關係,不然將拋出沒法找到導航屬性異常。博客