EntityFramework 7更新记录时出错

时间:2017-01-24 21:28:12

标签: c# entity-framework asp.net-core-mvc .net-core entity-framework-core

每次我想更新我的记录时,都会收到以下错误:

  

“无法跟踪实体类型'用户'的实例,因为另一个实例   已经跟踪了具有相同密钥的此类型的实例。什么时候   为大多数密钥类型添加新实体的唯一临时密钥值   如果没有设置密钥,则将创建(即,如果分配了密钥属性)   其类型的默认值)。如果您明确设置密钥   新实体的值,确保它们不会与现有实体发生冲突   为其他新实体生成的实体或临时值。什么时候   附加现有实体,确保只有一个实体实例   给定的键值附加到上下文中。“

这是我的代码:

public void SaveRecipient(Recipient myRecipient)
{
    if (myRecipient.RecipientGUID == Guid.Empty)
    {
        myRecipient.RecipientGUID = Guid.NewGuid();

        foreach (ContactMethod tmpCM in myRecipient.ContactMethods)
        {
            context.Entry(tmpCM.Type).State = EntityState.Unchanged;
        }

        context.Entry(myRecipient.LastModifiedBy).State = EntityState.Unchanged;
        context.Entry(myRecipient.Owner).State = EntityState.Unchanged;
        context.Entry(myRecipient.CreatedBy).State = EntityState.Unchanged;

        context.Recipients.Add(myRecipient);
    }
    else
    {
        var dbRecipient = context.Recipients
            .Include(a => a.ContactMethods).ThenInclude(t => t.Type)
            .Include(b => b.CreatedBy)
            .Include(c => c.LastModifiedBy)
            .Include(d => d.Owner).ThenInclude(o => o.Users)
            .FirstOrDefault(x => x.RecipientGUID == myRecipient.RecipientGUID);

        if (dbRecipient != null)
        {
            dbRecipient.FirstName = myRecipient.FirstName;
            dbRecipient.LastName = myRecipient.LastName;
            dbRecipient.Company = myRecipient.Company;

            foreach (ContactMethod tmpCM in myRecipient.ContactMethods)
            {
                var dbCM = dbRecipient.ContactMethods.FirstOrDefault(x => x.ContactMethodGUID == tmpCM.ContactMethodGUID);

                if (dbCM != null)
                {
                    dbCM.CountryCode = tmpCM.CountryCode;
                    dbCM.Identifier = tmpCM.Identifier;
                    dbCM.IsPreferred = tmpCM.IsPreferred;
                }
                else
                {
                    dbRecipient.ContactMethods.Add(tmpCM);
                }
            }

            //Only update this if it has changed.
            if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID)
            {
                dbRecipient.LastModifiedBy = myRecipient.LastModifiedBy;
            }

            dbRecipient.LastModifiedOn = myRecipient.LastModifiedOn;
        }
    }

    context.SaveChanges();
}

相关课程:

用户:

public class User
    {
        [Key]
        public Guid UserGUID { get; set; }

        public string UserName { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public string Email { get; set; }

        public bool IsSiteAdmin { get; set; }

        public bool IsActive { get; set; }

        public DateTime? CreatedOn { get; set; }

        public DateTime? LastLogin { get; set; }
    }

收件人:

public class Recipient
    {
        [Key]
        public Guid RecipientGUID { get; set; }

        [Required(ErrorMessage = "Please enter a Recipient's First Name.")]
        public string FirstName { get; set; }

        [Required(ErrorMessage = "Please enter a Recipient's Last Name.")]
        public string LastName { get; set; }

        public string Company { get; set; }

        public UserGroup Owner { get; set; }

        public virtual ICollection<ContactMethod> ContactMethods { get; set; }

        public User CreatedBy { get; set; }

        public DateTime CreatedOn { get; set; }

        public User LastModifiedBy { get; set; }

        public DateTime LastModifiedOn { get; set; }

        public bool IsActive { get; set; }
    }

联系方式:

public class ContactMethod
    {
        [Key]
        [HiddenInput(DisplayValue = false)]
        public Guid ContactMethodGUID { get; set; }

        [ForeignKey("ContactMethodTypeGUID")]
        public virtual ContactMethodType Type { get; set; }

        public string CountryCode { get; set; }

        [Required]
        public string Identifier { get; set; }

        public bool IsPreferred { get; set; }

        [ForeignKey("RecipientGUID")]
        public virtual Recipient Owner { get; set; }
    }

当我想要更新收件人时,会发生此问题,而另一个用户正在进行更新。所以说用户abcd做了最后一次更新,但现在用户zyx更新了记录。因此Recipeint.LastUpdatedBy设置为当前会话用户。当我这样做时,我得到上述错误。我无法弄清楚如何超越这个。

小记:如果我加上这个:

context.Entry(myRecipient.LastModifiedBy).State = EntityState.Unchanged;
if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID)

中的

语句,并说用户lastmodifiedby设置为user abc。现在User asfg第一次更新此收件人,它会通过,LastModifiedBy将设置为user asfg,但是说用户abc返回并再次更改收件人,所以lastmodifiedby返回abc,它失败,出现同样的错误

这让我疯了,我无法弄清楚!!!

1 个答案:

答案 0 :(得分:1)

我从微软 Arthur Vickers 得到了答案。我想分享。

设置导航属性dbRecipient.LastModifiedBy的代码将其设置为未被上下文跟踪的实体实例。在这种情况下,上下文似乎已经跟踪了同一实体的另一个实例 - 可能是因为它是通过包含CreatedBy导航的查询引入的。 EF无法跟踪同一实体的两个实例,这就是抛出异常的原因,因此您需要在此处提供EF附加信息以了解该做什么。在一般情况下,这可能很复杂 例如:如果被跟踪的实例具有已在另一个实例中修改过的属性 但是,假设情况并非如此,那么您只需查找正在跟踪的实例并使用它,例如:

if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID)
{
    dbRecipient.LastModifiedBy = test.Set<User>().Find(myRecipient.LastModifiedBy.UserGUID);
}