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

2023-09-04 23:06:42 作者:童谣

错误消息:连接类型的实体失败,因为同类型的另一实体已经有相同的主键值

Error message: Attaching an entity of type failed because another entity of the same type already has the same primary key value.

问:我如何连接以类似的方式的实体表现在以下code中的AttachActivity方法

Question: How do I attached an entity in a similar fashion as demonstrated in the AttachActivity method in the code below?

我要承担上述错误信息的其他单位的部分是指一个对象存在于内存中,但超出范围(??)。我注意到这一点,因为DBSet为实体类型的本地属性,我试图附加返回零。

I have to assume the "another entity" part of the error message above refers to an object that exists in memory but is out of scope (??). I note this because the Local property of the DBSet for the entity type I am trying to attach returns zero.

我有理由相信实体没有在上下文中存在,因为我逐步完成code和观看环境,因为它是创建。这些实体被添加了几行字后立即创建的DbContext的。

I am reasonably confident the entities do not exist in the context because I step through the code and watch the context as it is created. The entities are added in the few lines immediately following creation of the dbcontext.

正在测试用于连接实体,那么具体:what是最合理的方式,以找出是否实体连接到的DbContext或不?

Am testing for attached entities as specified here:what is the most reasonable way to find out if entity is attached to dbContext or not?

当看着在Visual Studio当地人窗口,我看不出有任何的实体类型的活动(无论ID的),除了一个我试图附加当地人。

When looking at locals in the locals window of visual studio I see no entities of type Activity (regardless of ID) except the one I am trying to attach.

在code按此顺序执行:尝试 - > ModifyProject - > AttachActivity

The code executes in this order: Try -> ModifyProject -> AttachActivity

code未能在AttachActivity在注释行。

Code fails in the AttachActivity at the commented line.

请注意调试意见,如果任何实体被添加到上下文,这将投掷之间的code

Note the code between the debug comments which will throw if any entities have been added to the context.

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:

This is the class that news up the 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;
            }
        }

我不是问:我如何使用AsNoTracking 什么区别.AsNoTracking()做什么呢?

推荐答案

一个解决方案,以避免收到此错误是使用查找方法。连接实体前,查询的DbContext 为所需的实体,如果实体存在于内存中,你得到,否则实体将被从数据库中检索本地实体。

One solution to avoid receive this error is using Find method. before attaching entity, query DbContext for desired entity, if entity exists in memory you get local entity otherwise entity will be retrieved from database.

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;
}