EntityFramework 7更新記錄時出錯

.net-core asp.net-core-mvc c# entity-framework entity-framework-core

每次我想更新我的記錄時,我都會收到以下錯誤:

“無法跟踪實體類型'User'的實例,因為已經跟踪了具有相同鍵的此類型的另一個實例。添加新實體時,對於大多數鍵類型,如果未設置鍵,將創建唯一的臨時鍵值(即如果為key屬性分配了其類型的默認值。如果您明確設置新實體的鍵值,請確保它們不會與現有實體或為其他新實體生成的臨時值發生衝突。附加現有實體時,請確保只有一個具有給定鍵值的實體實例附加到上下文。“

這是我的代碼:

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,它失敗,出現同樣的錯誤。

這讓我瘋了,我無法理解!

熱門答案

我從微軟的 Arthur Vickers那裡得到了答案。我想分享。

設置導航屬性dbRecipient.LastModifiedBy的代碼將其設置為未被上下文跟踪的實體實例。在這種情況下,上下文似乎已經跟踪了同一實體的另一個實例 - 可能是因為它是通過包含CreatedBy導航的查詢CreatedBy
EF無法跟踪同一實體的兩個實例,這就是拋出異常的原因,因此您需要在此處提供EF附加信息以了解該做什麼。在一般情況下,這可能很複雜。
例如:如果被跟踪的實例具有已在另一個實例中修改的屬性。
但是,假設情況並非如此,那麼您只需查找正在跟踪的實例並使用它,例如:

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


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow