zoukankan      html  css  js  c++  java
  • 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();
            }
        }
    }

    结果如下:

  • 相关阅读:
    HDU 2639 Bone Collector II (01背包,第k解)
    POJ 2184 Cow Exhibition 奶牛展(01背包,变形)
    hihoCoder #1165 : 益智游戏 (挑战赛11 B题)
    UVA 562 Dividing coins 分硬币(01背包,简单变形)
    POJ Charm Bracelet 挑饰品 (常规01背包)
    hiho一下 第四十四周 博弈游戏·Nim游戏(直接公式解)
    UVA 624 CD(01背包,要记录路径)
    118 Pascal's Triangle 帕斯卡三角形 杨辉三角形
    117 Populating Next Right Pointers in Each Node II 每个节点的右向指针 II
    116 Populating Next Right Pointers in Each Node 每个节点的右向指针
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/9799823.html
Copyright © 2011-2022 走看看