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. 不可改变性imutable

    不可改变性是指一些对象在被创建之后不会因为某些方式改变,特别是针对任何可以改变哈希对象的哈希值的方式. 两者相联系是因为哈希键值一定是不可改变的,所以它们对应的哈希键值也不改变. 如果允许它们改变,那 ...

  2. Centos7 linux下通过源码安装redis以及使用

    下载redis安装包 wget http://download.redis.io/releases/redis-5.0.3.tar.gz 解压压缩包 tar -zxvf redis-.tar.gz y ...

  3. eclipse中svn项目重定向地址

    有这种需求,一般是把项目提交到IP地址已经跟换的服务器,无法连接服务器再提交项目,比较着急. 我们看看怎么办: ② ③

  4. R语言矩阵栅格显示矩阵颜色显示

    效果如下:

  5. 学习笔记24—win10环境下python版libsvm的安装

    1.前言 由于毕业设计需要用到libsvm,所以最近专心于配置libsvm,曾经尝试过在matlab中安装,但是没有成功.最终在Python环境中完成安装. 2.LIBSVM介绍 LIBSVM 是台湾 ...

  6. opencv4.0 cuda10 编译速度太慢

    opencv4.0 cuda10 对比不带cuda的时候,编译速度太慢,主要卡在cuda的编译上. 参考http://answers.opencv.org/question/5090/why-open ...

  7. (转)stm32启动文件详解

    在<<STM32不完全手册里面>>,用的是STM32F103RBT6,所有的例程都采用了一个叫STM32F10x.s的启动文件,里面定义了STM32的堆栈大小以及各种中断的名字 ...

  8. PhantomJS框架(初识无头浏览器)

    博主今天看到大神聊起 headless,首先我去了解了下这个概念  无头浏览器 selenium框架是有头浏览器的代表,即可看得见的浏览器 而headless browser无头浏览器,即看不见的浏览 ...

  9. asp.net网站服务器搭建之从零开始

    asp.net网站服务器搭建之从零开始 一 IIS(Internet Information Services)安装:  1.选择"控制面板".  2.点"添加或删除程序 ...

  10. 20170706xlVBA批量提取word表格中的自我评分

    单位里普遍存在各种低效率的办公行为,比如每年的自我评分.评分细目表为word文档,每行一个项目,每个项目要填写得分事项和分值,组长审核之后转成Excel向上递交.主要涉及到问题就是word文档中一列得 ...