• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
PowerCoder
博客园    首页    新随笔    联系   管理    订阅  订阅

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

在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();
        }
    }
}

结果如下:

 

posted @ 2018-10-16 18:32  PowerCoder  阅读(12020)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3