简体   繁体   English

带有 Automapper 的 EF Core 抛出异常“无法跟踪实体类型”

[英]EF Core with Automapper throw Exception 'Entity type cannot be tracked'

I have a problem with EF Core in combination with automapper.我在使用 EF Core 和 automapper 时遇到了问题。

My Solution contains this hierarchy:我的解决方案包含以下层次结构:

BLL <=> DAL <=> EF Core <=> Mysql Database

I use automapper in the BLL.我在 BLL 中使用 automapper。

And have as example this user class:并以这个用户类为例:

public class User
{
    public Guid Id { get; set; } = Guid.NewGuid();

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public Guid? CreatedById { get; set; }

    public Guid? ModifiedById { get; set; }

    public virtual User CreatedBy { get; set; }

    public virtual User ModifiedBy { get; set; }
}

And i have the same class for the UserDTO (DataTransferObject).我有相同的 UserDTO 类(DataTransferObject)。

I already have a record for an user in the database to create another user, because it's necessary to fill createdby and modifiedby to create or update a user.我在数据库中已经有一个用户创建另一个用户的记录,因为需要填写createdby和modifiedby来创建或更新一个用户。

Get the user from the database:从数据库中获取用户:

UserDTO userDTO = this._UserBLL.GetUser("Unit", "Test");

//BLL
var mapped = new List<UserDTO>();
this._Mapper.Map(dalResult, mapped); //dalResult = List<User> object
return mapped;

And here an example how to add a user:这是一个如何添加用户的示例:

UserDTO testUser2 = new UserDTO
{
    FirstName = "Test 2",
    LastName = "Test 2",
    CreatedBy = userDTO,
    ModifiedBy = userDTO
};

this._UserBLL.Add(testUser2);

//BLL
List<User> mappedUsers = new List<User>();

this._Mapper.Map(users, mappedUsers); //users = List<UserDTO> that contains testUser2

DbContext.Users.AddRange(mappedUsers); //Throws exception
DbContext.SaveChanges();

The Exception that is thrown: The instance of entity type 'User' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked.抛出的异常: The instance of entity type 'User' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked.

But i dont know how to solve the exception.但我不知道如何解决异常。 Same issue is, when i update an existing record.同样的问题是,当我更新现有记录时。

AutoMapping class is: AutoMapping 类是:

this.CreateMap<User, UserDTO>()
    .ReverseMap();

Do u have an idea how to fix this?你知道如何解决这个问题吗? I hope you understand my problem, else not, ask me.我希望你明白我的问题,否则,问我。

King regards国王问候

There are a couple of misconceptions here这里有几个误解

  1. Bare in mind that a DTO is a dumb class, in a sense that it does nothing but serving as a container for the information to travel in a strongly typed way.请记住,DTO 是一个愚蠢的类,从某种意义上说,它只是充当信息以强类型方式传播的容器。 You will be normally dealing with DTOs when the front-end send you some data and your backend catches on the controller parameter (I know this is not exactly true, just trying to make a point here), or when returning a DTO to the front end to whatever reason it needs.当前端向您发送一些数据并且您的后端捕获控制器参数时,您通常会处理 DTO(我知道这不完全正确,只是想在这里说明一点),或者在将 DTO 返回到前端时以任何它需要的理由结束。 The general approach then will be:那么一般的方法是:

  2. Frontend sent a DTO前端发送了一个 DTO

  3. Backend controller catches后端控制器捕获

  4. Backend services map the DTO to some domain model of interest (automapper)后端服务将 DTO 映射到一些感兴趣的域模型(自动映射器)

  5. Backend services perform the logical steps of the business rules such as saving a record on the database or updating something I don't know you name it后端服务执行业务规则的逻辑步骤,例如在数据库中保存记录或更新我不知道你命名的内容

  6. Backend service map the response (if any) to a DTO (automapper)后端服务将响应(如果有)映射到 DTO(自动映射器)

  7. Backend controller sends the data right back to the front end, to do whatever it needs to do后端控制器将数据直接发送回前端,以做它需要做的任何事情

Now, regarding your bug it's a common bug of entity frameworks begginers.现在,关于您的错误,这是实体框架初学者的常见错误。 Let me ilustrate what happend:让我说明发生了什么:

UserDTO userDTO = this._UserBLL.GetUser("Unit", "Test"); 
//tip: as per the explanation above this should't be a DTO

//EF says "alright!, programmer pull out
//a record from the database and got a object of type UserDTO with Id = "someguid"
//im gonna begin tracking this object to see if it changes in the
//execution of the code.
//In case my fellow programmer wants to modify this object and 
//save it in on the database, as I was tracking it down in 
//the first place, I'm gonna know how to build my
//SQL statements to perform the right update/delete/create sentence in 
//SQL form.

Somewhere over the mapping you are creating the same object type with the same Id and then entity framework go bananas在映射的某个地方,您正在创建具有相同 Id 的相同对象类型,然后实体框架变得疯狂

//EF says: "mmm, that's weird, im tracking the same object 
//again, im gonna alert the human. *throws exception*

The key here is to re-read the documentation of entity framework/core to fully understand how entity framework think Now, regarding your code and business requirement, you should be aiming to do something like this:这里的关键是重新阅读实体框架/核心的文档,以充分了解实体框架的想法现在,关于您的代码和业务需求,您的目标应该是做这样的事情:

//Suppose that the in the controller parameter we receive this DTO
var newUserDto = new UserDto() 
{
    Firstname = "Rodrigo",
    Lastname = "Ramirez",
    CreatedBy = 1, //this can be the user Id of the user that sent this DTO
};

var userToCreate = Mapper.Map<User>(newUserDto);
var userCreator = UserRepository.GetById(newUserDto.CreatedBy);
userToCreate.CreatedBy = userCreator;

final words on this topic:关于这个话题的最后一句话:

  1. It's a matter of preferences but I do rather read这是一个偏好问题,但我宁愿阅读
var user = Mapper.Map<User>(newUserDto); //hey mapper, be a pal and transform this newUserDto into a User object.
  1. Check that you are using List<> to map when you don't need to.检查您是否在不需要时使用 List<> 进行映射。
  2. For this business logic, you don't need to prevent entity framework to begin tracking a given entity.对于此业务逻辑,您无需阻止实体框架开始跟踪给定实体。 But in case you find such case you can checkout the method "AsNoTracking()" that does that.但是,如果您发现这种情况,您可以查看执行此操作的方法“AsNoTracking()”。
  3. Review the necesity of create a new GUID over User class instantiation.查看在 User 类实例化上创建新 GUID 的必要性。 This seems to be buggy and you need to fully understand how EF works in order to succed with this practice.这似乎有问题,您需要完全了解 EF 的工作原理才能成功完成此实践。
  4. The thing you want to do is a common audit practice, and it's advisable that you override the method OnSaveChanges() to perform this task.您想要做的是一种常见的审计实践,建议您重写 OnSaveChanges() 方法来执行此任务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 EF Core:无法跟踪实体类型的实例,并且无法注入上下文依赖项 - EF Core: The instance of entity type cannot be tracked and context dependency injection InvalidOperationException:无法跟踪实体实例 - EF Core - InvalidOperationException: The instance of entity cannot be tracked - EF Core 无法跟踪实体类型的实例,因为另一个实例...更新数据库时出现 EF Core 错误 - The instance of entity type cannot be tracked because another instance… EF Core error when updating db EF Core:无法跟踪实体类型的实例,因为另一个实例具有相同的键值 - EF Core: The instance of entity type cannot be tracked because another instance with the same key value EF Core(内存数据库)-'无法跟踪实体类型 X 的实例,因为另一个具有键值的实例 - EF Core (in-memory database) - 'The instance of entity type X cannot be tracked because another instance with the key value EF:无法跟踪实体类型X的实例,因为已经跟踪了具有相同密钥的此类型的另一个实例 - EF: The instance of entity type X cannot be tracked because another instance of this type with the same key is already being tracked 实体框架核心 - 无法跟踪实体类型的实例,因为已在跟踪具有键值的另一个实例 - Entity framework Core - The instance of entity type cannot be tracked because another instance with the key value is already being tracked EF Core 已跟踪具有相同 ID 的实体 - EF Core already tracked entity with same id 无法跟踪实体类型的实例 - The instance of entity type cannot be tracked 实体类型“”的实例无法跟踪 - The instance of entity type '' cannot be tracked
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM