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,但是前提是必须显式配置映射关系,否则将抛出无法找到导航属性异常。

 


为了方便大家在移动端也能看到我分享的博文,现已注册个人公众号,扫描上方左边二维码即可,欢迎大家关注,有时间会及时分享相关技术博文。

感谢花时间阅读此篇文章,如果您觉得这篇文章你学到了东西也是为了犒劳下博主的码字不易不妨打赏一下吧,让楼主能喝上一杯咖啡,在此谢过了!
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!
本文版权归作者和博客园共有,来源网址:http://www.cnblogs.com/CreateMyself)/欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   Jeffcky  阅读(1818)  评论(12编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示