EntityFramework 6.x和EntityFramework Core關系映射中導航屬性必須是public?


前言

不知我們是否思考過一個問題,在關系映射中對於導航屬性的訪問修飾符是否一定必須為public呢?如果從未想過這個問題,那么我們接下來來探討這個問題。

EF 6.x和EF Core 何種情況下必須配置映射關系?

在EF 6.x中我們創建如下示例類。

    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),接下來我們來看下:

            using (var ctx = new EfDbContext())
            {
                ctx.Database.Log = Console.WriteLine;

                var customers = ctx.Customers.Include(d => d.Orders).ToList();
            };

這樣是我們一直以來最正常的操作,如前言所敘,那么導航屬性難道必須是public嗎?接下來我們來試試。我們嘗試將Orders導航屬性配置成如下私有的。

 private ICollection<Order> Orders { get; set; } = new List<Order>();

因為其為私有,若通過lambda表達式肯定是訪問受限制,那么我們改為通過基於字符串的方式來顯式加載,如下:

            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則可以,前提是必須顯式配置映射關系,否則也不行,如下:

 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看看。

 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,但是前提是必須顯式配置映射關系,否則將拋出無法找到導航屬性異常。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM