EF Core 现在不支持多对多映射,只能做2个一对多映射.

而EF Core 的一对多映射,采用约定大于配置. 默认的外键字段名是(引用实体名+主键名, 或者引用实体的主键名)

 public class Product
{
[Key]
public int ProdId{ get; set; } public String ProdCode{ get; set; }
public String ProdName{ get; set; } public IList<CategoryProduct> CategoryProducts { get; set; }
}
public class Category
{
[Key]
public int CategoryId{ get; set; }
public String CategoryCode { get; set; }
public String CategoryName{ get; set; } public IList<CategoryProduct> CategoryProducts { get; set; }
}

例如Product实体里有一个Category类的字段. 对应的SQL语句,就会在Product表里查找CategoryCategoryId的字段,或者是CategoryId的字段

参考这个 https://docs.microsoft.com/zh-cn/ef/core/modeling/relationships

比如Product和Category 我现在定义Product和Category是多对多关系.

那么实体定义如下:

   /// <summary>
/// EF CORE 处理Many to Many关系,要转成两个 One to Many
/// https://docs.microsoft.com/en-us/ef/core/modeling/relationships
/// </summary>
public class CategoryProduct
{
public int Id { get; set; }
public int CategoryId{ get; set; }
public Category Category { get; set; }
public int ProdId { get; set; }
public Product Product { get; set; }
}

在context的OnModelCreating方法指定mapping

        protected override void OnModelCreating(ModelBuilder modelBuilder)
{ //多对多关系,要手工指定
modelBuilder.Entity<CategoryProduct>().HasKey(x => new { x.CategoryId, x.ProdId }); //指定中间表主键 modelBuilder.Entity<CategoryProduct>().HasOne(cp => cp.Category)
.WithMany(c => c.CategoryProducts)
.HasForeignKey(cp => cp.CategoryId); modelBuilder.Entity<CategoryProduct>().HasOne(cp => cp.Product)
.WithMany(c => c.CategoryProducts)
.HasForeignKey(cp => cp.ProdId); }

但是我很困惑,这样的写法, 我在Category里的CategoryProducts的Collection 有什么用呢?

比如我要找CategroyId=1的所有产品信息,我觉得最直观的写法的是context.categories.Where(t=>t.CategoryId==1).FirstOrDefault().Products.toList()这样的写法.

它现在却要这样写

 _context.CategoryProducts.Where(x => x.CategoryId.Equals()).Include(x=>x.Product).Select(x=>x.Product).ToList();

或者这样写

            var prodIdList = _context.CategoryProducts.Where(x => x.CategoryId.Equals(1)).Select(x=>x.ProdId);
var qry = _context.Products.Where(x => prodIdList.Contains(x.ProdId)).ToList(); var result = new { total = qry.Count(), rows = qry.ToList() };
return Json(result);

这样需要查询2次,在NLOG的日志里可以看到

2018-04-15 22:33:56.9887|1|INFO|Microsoft.AspNetCore.Hosting.Internal.WebHost|Request starting HTTP/1.1 GET http://localhost:5001/CRM/Product/ListCategoryProducts/1
2018-04-15 22:33:57.0437|24|INFO|Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware|No cached response available for this request.
2018-04-15 22:33:57.2326|1|INFO|Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker|Executing action method FoxCRMCore.Controllers.CRM.ProductController.ListCategoryProducts (FoxCRMCore) with arguments (1) - ModelState is Valid
2018-04-15 22:33:58.7572|10403|INFO|Microsoft.EntityFrameworkCore.Infrastructure|Entity Framework Core 2.0.2-rtm-10011 initialized 'CRMContext' using provider 'Pomelo.EntityFrameworkCore.MySql' with options: MaxPoolSize=128
2018-04-15 22:33:59.4957|20101|INFO|Microsoft.EntityFrameworkCore.Database.Command|Executed DbCommand (73ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30']
SELECT `x`.`CategoryId`, `x`.`CategoryCode`, `x`.`CategoryName`, `x`.`CreateDate`, `x`.`CreateUser`, `x`.`IsActive`, `x`.`ModifyDate`, `x`.`ModifyUser`, `x`.`SYSId`
FROM `CRMCategory` AS `x`
WHERE `x`.`CategoryId` = @__id_0
2018-04-15 22:33:59.7948|20101|INFO|Microsoft.EntityFrameworkCore.Database.Command|Executed DbCommand (9ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30']
SELECT `x`.`ProdId`, `x`.`CreateDate`, `x`.`CreateUser`, `x`.`IsActive`, `x`.`ModifyDate`, `x`.`ModifyUser`, `x`.`ProdCode`, `x`.`ProdFullName`, `x`.`ProdName`, `x`.`SYSId`
FROM `CRMProduct` AS `x`
WHERE `x`.`ProdId` IN (
SELECT `x0`.`ProdId`
FROM `CRMCategoryProduct` AS `x0`
WHERE `x0`.`CategoryId` = @__id_0
)
2018-04-15 22:33:59.8546|1|INFO|Microsoft.AspNetCore.Mvc.Formatters.Json.Internal.JsonResultExecutor|Executing JsonResult, writing value { total = 2, rows = System.Collections.Generic.List`1[FoxCRMCore.Models.PD.Product] }.
2018-04-15 22:33:59.8996|2|INFO|Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker|Executed action FoxCRMCore.Controllers.CRM.ProductController.ListCategoryProducts (FoxCRMCore) in 2753.674ms

如果Category和Product是1对多关系.

    public class Product
{
[Key]
public int ProdId{ get; set; } public String ProdCode{ get; set; }
public String ProdName{ get; set; }

public int CategoryId { get; set; }

public Category Category { get; set; } //1对多
}
public class Category
{
[Key]
public int CategoryId{ get; set; }
public String CategoryCode { get; set; }
public String CategoryName{ get; set; }

public IList<Product> Products { get; set; }
}

在context的OnModelCreating方法指定mapping

            modelBuilder.Entity<Product>().HasOne(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId);

比如我要找CategroyId=1的所有产品信息,写法如下:

(因为用了Include,它会一直循环eagerLoad collection, 找Category对应的Products,然后再找Products的Category,如果转成Json就死循环了.所以用Select只显示部分字段)

Json.JsonSerializationException: Self referencing loop detected, 另一个方案是在Product的Category字段加上[IgnoreDataMember]  (using System.Runtime.Serialization;)

            var cat = _context.Categories.Where(x => x.CategoryId.Equals(id)).Include(x=>x.Products).FirstOrDefault();
var qry = cat.Products.Select(x=> new {x.ProdId,
x.ProdCode,
x.ProdName,
x.ProdFullName,
x.CategoryId,
x.Category.
CategoryName}); var result = new { total = qry.Count(), rows = qry.ToList() };
return Json(result);

NLOG日志显示,也是查询2次

2018-04-15 23:28:54.7770|20101|INFO|Microsoft.EntityFrameworkCore.Database.Command|Executed DbCommand (68ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30']
SELECT `x`.`CategoryId`, `x`.`CategoryCode`, `x`.`CategoryName`, `x`.`CreateDate`, `x`.`CreateUser`, `x`.`IsActive`, `x`.`ModifyDate`, `x`.`ModifyUser`, `x`.`SYSId`
FROM `CRMCategory` AS `x`
WHERE `x`.`CategoryId` = @__id_0
ORDER BY `x`.`CategoryId`
LIMIT 1
2018-04-15 23:28:54.9476|20101|INFO|Microsoft.EntityFrameworkCore.Database.Command|Executed DbCommand (0ms) [Parameters=[@__id_0='?'], CommandType='Text', CommandTimeout='30']
SELECT `x.Products`.`ProdId`, `x.Products`.`CategoryId`, `x.Products`.`CreateDate`, `x.Products`.`CreateUser`, `x.Products`.`IsActive`, `x.Products`.`ModifyDate`, `x.Products`.`ModifyUser`, `x.Products`.`ProdCode`, `x.Products`.`ProdFullName`, `x.Products`.`ProdName`, `x.Products`.`SYSId`
FROM `CRMProduct` AS `x.Products`
INNER JOIN (
SELECT `x0`.`CategoryId`
FROM `CRMCategory` AS `x0`
WHERE `x0`.`CategoryId` = @__id_0
ORDER BY `x0`.`CategoryId`
LIMIT 1
) AS `t` ON `x.Products`.`CategoryId` = `t`.`CategoryId`
ORDER BY `t`.`CategoryId`

EF Core ThenInclude 自动完成提示,不会提示子对象的关联对象. 你写完再看,就会提示正确的.
https://github.com/dotnet/roslyn/issues/8237

把旧系统迁移到.Net Core 2.0 日记(10) -- EF core 和之前版本多对多映射区别的更多相关文章

  1. 把旧系统迁移到.Net Core 2.0 日记 (15) --Session 改用Redis

    安装Microsoft.Extensions.Caching.Redis.Core NuGet中搜索Microsoft.Extensions.Caching.Redis.Core并安装,此NuGet包 ...

  2. 把旧系统迁移到.Net Core 2.0 日记(1) - Startup.cs 解析

    因为自己到开发电脑转到Mac Air,之前的Webform/MVC应用在Mac 跑不起来,而且.Net Core 2.0 已经比较稳定了. 1. 为什么会有跨平台的.Net Core  近年来,我们已 ...

  3. .NET Core 1.0、ASP.NET Core 1.0和EF Core 1.0简介

    .NET Core 1.0.ASP.NET Core 1.0和EF Core 1.0简介 英文原文:Reintroducing .NET Core 1.0, ASP.NET Core 1.0, and ...

  4. Professional C# 6 and .NET Core 1.0 - 40 ASP.NET Core

    本文内容为转载,重新排版以供学习研究.如有侵权,请联系作者删除. 转载请注明本文出处:Professional C# 6 and .NET Core 1.0 - 40 ASP.NET Core --- ...

  5. .NET Core 2.0和ASP.NET Core 2.0正式版抢先体验

    .NET Core 2.0和ASP.NET Core 2.0正式版抢先体验 .NET Standard 2.0 is final Broad platform support. .NET Standa ...

  6. ASP.NET Core 1.0、ASP.NET MVC Core 1.0和Entity Framework Core 1.0

    ASP.NET 5.0 将改名为 ASP.NET Core 1.0 ASP.NET MVC 6  将改名为 ASP.NET MVC Core 1.0 Entity Framework 7.0    将 ...

  7. [转帖]2016年时的新闻:ASP.NET Core 1.0、ASP.NET MVC Core 1.0和Entity Framework Core 1.0

    ASP.NET Core 1.0.ASP.NET MVC Core 1.0和Entity Framework Core 1.0 http://www.cnblogs.com/webapi/p/5673 ...

  8. 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获

    项目开发中的一些注意事项以及技巧总结   1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...

  9. 把旧系统迁移到.Net Core 2.0 日记 (12) --发布遇到的问题

    1. 开发时是在Mac+MySql, 尝试发布时是在SQL2005+Win 2008 (第一版) 在Startup.cs里,数据库连接要改,分页时netcore默认是用offset关键字分页, 如果用 ...

随机推荐

  1. 深究CSS中Position的属性和特性

    一.position的概念 作为布局必不可缺少的元素之一,深究其属性以及一些注意点是非常必要的. 定义:规定元素的定位类型. position属性: 属性 描述 常用性 absolute 生成绝对定位 ...

  2. 后端调用接口在通过webService发布 解决跨域问题

    1.新建一个空的项目 2.添加一个WebService新项   asmx格式的 3.在这里面写方法  加上[WebMethod]标识 前端就可以调用 4.发布WebService  右键服务  添加服 ...

  3. ArrayList list = new ArrayList()在这个泛型为Integer的ArrayList中存放一个String类型的对象

    java面试要点---ArrayList list = new ArrayList(); 在这个泛型为Integer的ArrayList中存放一个String类型的对象. ArrayList list ...

  4. Cordova 混合开发

    详细的教程在以下博客 https://blog.csdn.net/csdn100861/article/details/78585333

  5. FetchType.LAZY和FetchType.EAGER什么区别

    1.FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载. 2.FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载. ...

  6. 彻底搞懂 CPU 中的内存结构

    https://www.cnblogs.com/YJK923/p/10302180.html

  7. exam_review to M1

    1. 情态动词,尤其是can/can’t,should/shouldn’t. for example: You should have washed the wound.你应该已经洗好了伤口 Well ...

  8. POJ-2955 Brackets(括号匹配问题)

    题目链接:http://poj.org/problem?id=2955 这题要求求出一段括号序列的最大括号匹配数量 规则如下: the empty sequence is a regular brac ...

  9. android -------- 安装APK报错:Installation error: INSTALL_FAILED_UPDATE_INCOMPATIBLE解决方法

    记录一个 DELETE_FAILED_INTERNAL_ERROR Error while Installing APK问题 之前遇到这个问题 方案1 将data/data/目录下该应用的包名的目录删 ...

  10. Confluence 6 归档一个空间

    当你认为一个空间不再需要实时进行编辑,但你还希望在后面某个时候能够对空间重新进行访问编辑的时候,你可以对空间进行归档.归档一个空间,这样你可以让你归档的空间让最少的人能看见,但是你的空间还是可以在 C ...