在EF Core的DbContext中,我们可以通过DbContext或DbSet的Attach方法,来让DbContext上下文来跟踪(track)一个实体对象,假设现在我们有User实体对象,其UserCode为Key属性:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; namespace EFCoreDB.Entities
{
public partial class User
{
public User()
{
UserRole = new HashSet<UserRole>();
} public int Id { get; set; } [Key]
public string UserCode { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string MailAddress { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string CompanyCode { get; set; }
public DateTime? CreateTime { get; set; }
public int? DataStatus { get; set; } public ICollection<UserRole> UserRole { get; set; }
}
}

现在我们使用DbSet的Attach方法将两个UserCode都为"User001"的User实体Attach到一个DbContext:

using EFCoreDB.Entities;
using System; namespace EFCoreDB
{
class Program
{
static void Main(string[] args)
{
using (FinanceDigitalToolContext dbContext = new FinanceDigitalToolContext())
{
User user = new User() { UserCode = "User001", Username = "Tom" };
dbContext.User.Attach(user); user = new User() { UserCode = "User001", Username = "Jim" };
dbContext.User.Attach(user); dbContext.SaveChanges();
} Console.WriteLine("Press key to quit...."); Console.ReadLine();
}
}
}

运行结果如下:

结果在Attach第二个User实体的时候代码抛出了异常,异常信息如下:

The instance of entity type 'User' cannot be tracked because another instance with the same key value for {'UserCode'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

异常信息显示,当前DbContext中已经有一个相同UserCode值的实体被跟踪了,所以Attach第二个User实体的时候失败了。

同样如果我们改为用DbContext的Attach方法来添加第二个User实体也会失败:

using EFCoreDB.Entities;
using System; namespace EFCoreDB
{
class Program
{
static void Main(string[] args)
{
using (FinanceDigitalToolContext dbContext = new FinanceDigitalToolContext())
{
User user = new User() { UserCode = "User001", Username = "Tom" };
dbContext.User.Attach(user); user = new User() { UserCode = "User001", Username = "Jim" };
dbContext.Attach(user); dbContext.SaveChanges();
} Console.WriteLine("Press key to quit...."); Console.ReadLine();
}
}
}

但是如果现在我们Attach一个User实体的两个引用是不会报错的,如下所示:

using EFCoreDB.Entities;
using System; namespace EFCoreDB
{
class Program
{
static void Main(string[] args)
{
using (FinanceDigitalToolContext dbContext = new FinanceDigitalToolContext())
{
User user1 = new User() { UserCode = "User001", Username = "Tom" };//实体User的第一个引用user1
dbContext.User.Attach(user1);//Attach user1 User user2 = user1;//实体User的第二个引用user2,user1和user2实际上指向相同的User实体对象
dbContext.User.Attach(user2);//Attach user2,不会报错 dbContext.SaveChanges();
} Console.WriteLine("Press key to quit...."); Console.ReadLine();
}
}
}

结果如下,没有报错:

这说明当我们用Attach方法将一个User实体添加到EF Core的DbContext中进行跟踪时,DbContext会判断当前添加的实体是否和DbContext.ChangeTracker.Entries中被跟踪的所有实体是同一个对象,如果是同一个对象,那么其实只是把DbContext.ChangeTracker.Entries中所跟踪实体的EntityState更改为Unchanged,我们可以用下面代码来看看User实体两次Attach后的EntityState值:

using EFCoreDB.Entities;
using Microsoft.EntityFrameworkCore;
using System; namespace EFCoreDB
{
class Program
{
static void Main(string[] args)
{
using (FinanceDigitalToolContext dbContext = new FinanceDigitalToolContext())
{
User user1 = new User() { UserCode = "User001", Username = "Tom" };//实体User的第一个引用user1
dbContext.User.Attach(user1);//Attach user1
dbContext.Entry(user1).State = EntityState.Added;//修改user1实体的EntityState为Added
Console.WriteLine($"user1的EntityState为:{dbContext.Entry(user1).State.ToString()}");//显示user1实体的EntityState User user2 = user1;//实体User的第二个引用user2,user1和user2实际上指向相同的User实体对象
dbContext.User.Attach(user2);//Attach user2,不会报错
Console.WriteLine($"user1的EntityState为:{dbContext.Entry(user1).State.ToString()}");//显示user1实体的EntityState,Attach user2后,user1实体的EntityState变为Unchanged dbContext.SaveChanges();
} Console.WriteLine("Press key to quit...."); Console.ReadLine();
}
}
}

结果如下:

EF Core中Key属性相同的实体只能被跟踪(track)一次的更多相关文章

  1. EF Core中怎么实现自动更新实体的属性值到数据库

    我们在开发系统的时候,经常会遇到这种需求数据库表中的行被更新时需要自动更新某些列. 数据库 比如下面的Person表有一列UpdateTime,这列数据要求在行被更新后自动更新为系统的当前时间. Pe ...

  2. EF Core中如何通过实体集合属性删除从表的数据

    假设在数据库中有两个表:Person表和Book表,Person和Book是一对多关系 Person表数据: Book表数据: 可以看到数据库Book表中所有的数据都属于Person表中"F ...

  3. [小技巧]EF Core中如何获取上下文中操作过的实体

    原文地址:https://www.cnblogs.com/lwqlun/p/10576443.html 作者:Lamond Lu 源代码:https://github.com/lamondlu/EFC ...

  4. EF Core 中多次从数据库查询实体数据,DbContext跟踪实体的情况

    使用EF Core时,如果多次从数据库中查询一个表的同一行数据,DbContext中跟踪(track)的实体到底有几个呢?我们下面就分情况讨论下. 数据库 首先我们的数据库中有一个Person表,其建 ...

  5. 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)

    原文地址:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF 6 Code-F ...

  6. 9.4 翻译系列:EF 6以及 EF Core中的NotMapped特性(EF 6 Code-First系列)

    原文链接:http://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-f ...

  7. EF Core 中DbContext不会跟踪聚合方法和Join方法返回的结果,及FromSql方法使用讲解

    EF Core中: 如果调用Queryable.Count等聚合方法,不会导致DbContext跟踪(track)任何实体. 此外调用Queryable.Join方法返回的匿名类型也不会被DbCont ...

  8. EF Core中如何正确地设置两张表之间的关联关系

    数据库 假设现在我们在SQL Server数据库中有下面两张表: Person表,代表的是一个人: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ...

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

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

随机推荐

  1. JQuery的一些基础知识

    JQuery的核心的一些方法 each(callback) '就像循环$("Element").length; ‘元素的个数,是个属性$("Element"). ...

  2. IOC和DI到底是什么?

     在学习Spring框架的时候,我们总是能见到IOC这个单词,也时常听到DI这个词,那么他们分别是什么意思呢?接下来就讲讲个人对于这两个概念的理解  一.IOC和DI概念 IOC(控制反转):全称为: ...

  3. flask 继承模版的基本使用1

  4. NodeJS require路径

    项目需要用nodejs,感觉nodejs是前端装逼神器了,是通向全栈工程师的必经之路哇,接下来开始踏上学习nodejs的征程.下面是第一个hello,world的程序. 1.server.js文件,这 ...

  5. JavaScript中实现DI的原理

    什么是依赖注入 按照上面图的流程中我们可以知道我们需要实现这么几件事: 提供一个服务容器 为目标函数注册需要的依赖 获取目标函数注册的依赖项 通过依赖项来查询对应服务 将获取的依赖项传入目标函数 提供 ...

  6. mysql的一些sql用法

    mysql中修改列名: alter table 表名 change abc def 列类型;比如 alter table student change pws psw char(10);

  7. IE8下的怪异模式

    使用DWZ框架,老是出现点击button后在winxp IE8下出现新页面,经过检查后发现IE8下submit后,return false就不行了,必须使用window.event.returnVal ...

  8. PeekMessage&GetMessage

    原文:http://www.cnblogs.com/faceang/archive/2010/05/25/1743757.html PeekMessage与GetMessage的对比相同点:PeekM ...

  9. Java 多线程使用

    工作中遇到的问题,记录下解决的思路 问题: 对磁盘进行碎片化测试(比如说,磁盘空间是16G),从64K开始写文件,写满后删除一半,然后写32K 的数据,写满后删除一半...直到4K写满删除一般算是结束 ...

  10. Javascript之深入理解闭包

    闭包算是js里面比较不容易理解的点,尤其是对于没有编程基础的人来说. 其实闭包要注意的就那么几条,如果你都明白了那么征服它并不是什么难事儿.下面就让我们来谈一谈闭包的一些基本原理. 闭包的概念 一个闭 ...