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. 两个DIV并排显示

    今天做的一个项目,需要做3个div,一个是总框(Div1),另外两个是子框,按比例填满div1,我设置好两个div的width和height,发现效果是两个子div上下显示,如图所示: 要想将两个DI ...

  2. spring mvc 形参类型

    spring mvc 形参类型 1 没有占位符号的,形参的名字为参数的名称 请求路径为:organtrans/t1/t5?a=1(a为形参的的名称必须一致) @RequestMapping(" ...

  3. Ubuntu 编译安装 Xdebug

    安装xdebug 1.下载 https://xdebug.org/download.php 找到PHP5.6对应的版本 https://xdebug.org/files/xdebug-2.5.5.tg ...

  4. Xshell5中常用linux服务器命令集合

    简易版:http://www.zhimengzhe.com/linux/84546.html 详细版:http://www.cnblogs.com/peida/tag/%E6%AF%8F%E6%97% ...

  5. 前端调用接口报错看不到报错响应时 console.dir

    console.dir() 可以看到很多.log看不到的属性和方法

  6. java正则常用记录

    1.   java中 字符串的某个字母是否有某个指定字符N  : for(int i=0;i<temp.length();i++){ if( temp.get(i).substring(0,1) ...

  7. 力扣(LeetCode)1002. 查找常用字符

    给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表.例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 ...

  8. 推送消息 web push notification

    参考 : https://developers.google.com/web/fundamentals/engage-and-retain/push-notifications/   ( step b ...

  9. mongodb分享(二)

    上次讲的:查询find\findone\pretty.条件操作符 (大于.小于.大于等于.小于等于.不等于,$type).limit\skip.sort.Db.postjson.getIndexes( ...

  10. linux下编译C/C++ 程序

    C/C++的速度是Python和perl所无法比拟的,尤其对于处理超大的生物信息学文件来说. 最近在写一个最简单的fastq cut工具,Python简直慢到不能忍,8G的fastq.gz文件的cut ...