当前位置: 首页 > 知识库问答 >
问题:

附加类型的实体失败,因为另一个相同类型的实体已经具有相同的主键值

靳高明
2023-03-14

错误消息:附加类型的实体失败,因为相同类型的另一个实体已具有相同的主键值。

问题:我如何以类似于下面代码中AttachActivity方法所示的方式附加实体?

我必须假设上面错误消息的“另一个实体”部分指的是内存中存在但超出范围的对象(?)。我之所以注意到这一点,是因为我尝试附加的实体类型的DBSet的本地属性返回零。

我有理由相信实体不存在于上下文中,因为我遍历代码并在创建上下文时观察上下文。实体是在创建数据库上下文后立即添加的几行中。

Am测试此处指定的附加实体:找出实体是否附加到dbContext的最合理方法是什么?

在visual studio的“局部变量”窗口中查看局部变量时,除了我尝试附加的实体之外,我没有看到任何类型为Activity的实体(无论ID如何)。

代码按以下顺序执行:Try-

代码在附加活动中的注释行失败。

请注意调试注释之间的代码,如果已将任何实体添加到上下文中,这些注释将抛出。

private string AttachActivity(Activity activity)
    {
        string errorMsg = ValidateActivity(activity);  // has no code yet.  No. It does not query db.

        if(String.IsNullOrEmpty(errorMsg))
        {
            // debug 
            var state = db.Entry(activity).State; // Detached
            int activityCount = db.Activities.Local.Count;
            int projectCount = db.Activities.Local.Count;

            if (activityCount > 0 || projectCount > 0)
                throw new Exception("objects exist in dbcontext");
            // end debug
            if (activity.ID == 0)
                db.Activities.Add(activity);
            else
            {
                db.Activities.Attach(activity); // throws here
                db.Entry(activity).State = System.Data.Entity.EntityState.Modified;
            }
        }
        return errorMsg;
    }


public int ModifyProject(Presentation.PresProject presProject, out int id, out string errorMsg)
    {
        // snip

        foreach (PresActivity presActivity in presProject.Activities)
        {
            Activity a = presActivity.ToActivity();  // returns new Activity object
            errorMsg = ValidateActivity(a);          // has no code yet.  No. It does not query db.
            if (String.IsNullOrEmpty(errorMsg))
            {
                a.Project = project;
                project.Activities.Add(a);
                AttachActivity(a);
            }
            else
                break;
        }
        if (string.IsNullOrEmpty(errorMsg))
        {
            if (project.ID == 0)
                db.Projects.Add(project);
            else
                db.AttachAsModfied(project);
            saveCount = db.SaveChanges();
            id = project.ID;
        }
        return saveCount;
    }

这是更新dbContext的类:

public void Try(Action<IServices> work)
    {
        using(IServices client = GetClient())  // dbContext is newd up here
        {
            try
            {
                work(client);  // ModifyProject is called here
                HangUp(client, false);
            }
            catch (CommunicationException e)
            {
                HangUp(client, true);
            }
            catch (TimeoutException e)
            {
                HangUp(client, true);
            }
            catch (Exception e)
            {
                HangUp(client, true);
                throw;
            }
        }

我不是在问:我如何使用AsNoTrack。AsNoTrack()有什么区别?

共有3个答案

濮君植
2023-03-14

我通过如下更改更新方法解决了此错误。

如果您使用的是通用存储库和实体

_dbContext.Set<T>().AddOrUpdate(entityToBeUpdatedWithId);

或普通(非通用)存储库和实体

_dbContext.Set<TaskEntity>().AddOrUpdate(entityToBeUpdatedWithId);

如果使用AddOrUpdate()方法,请确保已添加系统。数据实体迁移命名空间。

衡丰茂
2023-03-14

附加类型为的实体失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“附加”方法或将实体状态设置为“未更改”或“已修改”时可能会发生这种情况。这可能是因为某些实体是新的,尚未收到数据库生成的键值。在这种情况下,请使用添加。

解决办法是

如果您必须使用GetAll()

public virtual IEnumerable<T> GetAll()
{
    return dbSet.ToList();
}

更改为

public virtual IEnumerable<T> GetAll()
{
    return dbSet.AsNoTracking().ToList();
}
黄信厚
2023-03-14

避免收到此错误的一种解决方案是使用查找方法。在附加实体之前,查询所需实体的上下文,若内存中存在实体,则获取本地实体,否则将从数据库中检索实体。

private void AttachActivity(Activity activity)
{
    var activityInDb = db.Activities.Find(activity.Id);

    // Activity does not exist in database and it's new one
    if(activityInDb == null)
    {
        db.Activities.Add(activity);
        return;
    }

    // Activity already exist in database and modify it
    db.Entry(activityInDb).CurrentValues.SetValues(activity);
    db.Entry(activityInDb ).State = EntityState.Modified;
}
 类似资料:
  • 让我快速描述一下我的问题。 我有5个客户的5个数据库,每个数据库都有一个名为SubnetSettings的表。 我已经创建了一个下拉列表来选择一个客户,并将显示属于所选客户的SubnetSSet表,并允许我创建、编辑和删除。 我可以毫无问题地创建、删除,但当我想编辑数据时,它会带来错误: /运输管理系统应用程序中的服务器错误。 附加“CFS”类型的实体。领域实体。SubnetSettings“失败

  • 错误消息: 正在附加“FaridCRMData”类型的实体。模型。“Customer”失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的 我的代码: FactorService. BaseService.cs:

  • 错误: 其他信息:附加“实体”类型的实体失败。客户”,因为另一个相同类型的实体已经具有相同的主键值。如果图中的任何实体具有冲突的键值,则使用“附加”方法或将实体的状态设置为“未更改”或“修改”时可能会发生这种情况。这可能是因为某些实体是新的并且没有收到数据库生成的键值。在这种情况下,使用“添加”方法或“添加”实体来跟踪图,然后根据需要将非新实体的状态设置为“未更改”或“修改”。 我的代码: 我是这

  • 我的WebApi应用程序有一个小问题。当我将新实体添加到我的数据库时,会出现这个问题。 实体: 要在其中向数据库中添加新赌注实体的代码: 在此位置,将我的实体添加到DB中(DB:我的SQL) 调用save方法时,代码会引发以下异常: 附加“WebCar. Domain. Entities. Lot”类型的实体失败,因为另一个相同类型的实体已经具有相同的主键值。如果图形中的任何实体具有冲突的键值,则

  • 我正在使用automapper重构一些代码,请参见下面注释掉的旧代码。 编辑:请注意,属性对象是从基础设置的,因此建议的重复问题不适用。 当状态设置为modified时,我得到以下异常:; 附加“M.Survey”类型的实体。ServiceLayer。模型属性“”失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实体状态设置为“U

  • 简而言之,在发布包装器模型并将一个条目的状态更改为“已修改”期间引发异常。更改状态之前,状态设置为“已分离”,但调用Attach()会引发相同的错误。我正在使用EF6。 请在下面找到我的代码(型号名称已更改以便于阅读) 模型 控制器 如上图所示 引发异常: 附加类型为“A”的实体失败,因为相同类型的另一个实体已具有相同的主键值。如果图形中的任何实体具有冲突的键值,则在使用“Attach”方法或将实