EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public?

前言

不知咱们是否思考过一个问题,在关系映射中对于导航属性的访问修饰符是否必定必须为public呢?若是从未想过这个问题,那么咱们接下来来探讨这个问题。ui

EF 6.x和EF Core 何种状况下必须配置映射关系?

在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,可是前提是必须显式配置映射关系,不然将抛出没法找到导航属性异常。博客

相关文章
相关标签/搜索