把旧系统迁移到.Net Core 2.0 日记(10) -- EF core 和之前版本多对多映射区别
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 和之前版本多对多映射区别的更多相关文章
- 把旧系统迁移到.Net Core 2.0 日记 (15) --Session 改用Redis
安装Microsoft.Extensions.Caching.Redis.Core NuGet中搜索Microsoft.Extensions.Caching.Redis.Core并安装,此NuGet包 ...
- 把旧系统迁移到.Net Core 2.0 日记(1) - Startup.cs 解析
因为自己到开发电脑转到Mac Air,之前的Webform/MVC应用在Mac 跑不起来,而且.Net Core 2.0 已经比较稳定了. 1. 为什么会有跨平台的.Net Core 近年来,我们已 ...
- .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 ...
- Professional C# 6 and .NET Core 1.0 - 40 ASP.NET Core
本文内容为转载,重新排版以供学习研究.如有侵权,请联系作者删除. 转载请注明本文出处:Professional C# 6 and .NET Core 1.0 - 40 ASP.NET Core --- ...
- .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 ...
- 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 将 ...
- [转帖]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 ...
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
项目开发中的一些注意事项以及技巧总结 1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...
- 把旧系统迁移到.Net Core 2.0 日记 (12) --发布遇到的问题
1. 开发时是在Mac+MySql, 尝试发布时是在SQL2005+Win 2008 (第一版) 在Startup.cs里,数据库连接要改,分页时netcore默认是用offset关键字分页, 如果用 ...
随机推荐
- 不可改变性imutable
不可改变性是指一些对象在被创建之后不会因为某些方式改变,特别是针对任何可以改变哈希对象的哈希值的方式. 两者相联系是因为哈希键值一定是不可改变的,所以它们对应的哈希键值也不改变. 如果允许它们改变,那 ...
- Centos7 linux下通过源码安装redis以及使用
下载redis安装包 wget http://download.redis.io/releases/redis-5.0.3.tar.gz 解压压缩包 tar -zxvf redis-.tar.gz y ...
- eclipse中svn项目重定向地址
有这种需求,一般是把项目提交到IP地址已经跟换的服务器,无法连接服务器再提交项目,比较着急. 我们看看怎么办: ② ③
- R语言矩阵栅格显示矩阵颜色显示
效果如下:
- 学习笔记24—win10环境下python版libsvm的安装
1.前言 由于毕业设计需要用到libsvm,所以最近专心于配置libsvm,曾经尝试过在matlab中安装,但是没有成功.最终在Python环境中完成安装. 2.LIBSVM介绍 LIBSVM 是台湾 ...
- opencv4.0 cuda10 编译速度太慢
opencv4.0 cuda10 对比不带cuda的时候,编译速度太慢,主要卡在cuda的编译上. 参考http://answers.opencv.org/question/5090/why-open ...
- (转)stm32启动文件详解
在<<STM32不完全手册里面>>,用的是STM32F103RBT6,所有的例程都采用了一个叫STM32F10x.s的启动文件,里面定义了STM32的堆栈大小以及各种中断的名字 ...
- PhantomJS框架(初识无头浏览器)
博主今天看到大神聊起 headless,首先我去了解了下这个概念 无头浏览器 selenium框架是有头浏览器的代表,即可看得见的浏览器 而headless browser无头浏览器,即看不见的浏览 ...
- asp.net网站服务器搭建之从零开始
asp.net网站服务器搭建之从零开始 一 IIS(Internet Information Services)安装: 1.选择"控制面板". 2.点"添加或删除程序 ...
- 20170706xlVBA批量提取word表格中的自我评分
单位里普遍存在各种低效率的办公行为,比如每年的自我评分.评分细目表为word文档,每行一个项目,每个项目要填写得分事项和分值,组长审核之后转成Excel向上递交.主要涉及到问题就是word文档中一列得 ...