简体   繁体   English

EntityFramework 7 更新记录时出错

[英]EntityFramework 7 Error when updating record

Every time I want to updated my record, I am getting the following error:每次我想更新我的记录时,我都会收到以下错误:

"The instance of entity type 'User' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (ie if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context." “无法跟踪实体类型 'User' 的实例,因为已在跟踪具有相同键的此类型的另一个实例。添加新实体时,对于大多数键类型,如果未设置键,将创建唯一的临时键值(即如果键属性为其类型分配了默认值。如果您为新实体明确设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。”

Here is my code:这是我的代码:

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

The relevant classes:相关类:

User:用户:

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

Recipient:接受者:

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

Contact Methods:联系方式:

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

This issue happens when I want to update a recipient, and it is another user doing the updating.当我想更新收件人时会发生此问题,并且是另一个用户进行更新。 So say user abcd did the last update, but now user zyx updates the record.所以说用户 abcd 做了最后一次更新,但现在用户 zyx 更新了记录。 So the Recipeint.LastUpdatedBy is set to the current Session User.因此 Recipeint.LastUpdatedBy 设置为当前会话用户。 When I do that, I get the above error.当我这样做时,我收到上述错误。 I cannot figure out how to get beyond this.我不知道如何超越这一点。

A small note: if I add this:一个小提示:如果我添加这个:

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

in the if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID)if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID)

statement, and say user lastmodifiedby is set to user abc.语句,并说用户 lastmodifiedby 设置为用户 abc。 Now User asfg updates this recipient for the first time, it goes through, and LastModifiedBy will be set to user asfg, but say user abc goes back and changes the recipient again, so lastmodifiedby goes back to abc, it fails, with the same error.现在用户 asfg 第一次更新这个接收者,它通过,并且 LastModifiedBy 将被设置为用户 asfg,但是说用户 abc 返回并再次更改接收者,所以 lastmodifiedby 返回到 abc,它失败,出现同样的错误.

this is driving me nuts and I cannot figure it out!!!这让我发疯,我无法弄清楚!!!

I got the answer to this from Arthur Vickers at Microsoft .我从Microsoft 的Arthur Vickers那里得到了答案。 I wanted to share.我想分享。

The code that sets the navigation property dbRecipient.LastModifiedBy is setting it to an entity instance that is not being tracked by the context.设置导航属性dbRecipient.LastModifiedBy的代码将其设置为上下文未跟踪的实体实例。 It seems like in this case the context is already tracking another instance for this same entity--presumably because it was brought in by the query through including the CreatedBy navigation.在这种情况下,上下文似乎已经在跟踪同一实体的另一个实例——大概是因为它是通过包含CreatedBy导航由查询CreatedBy
EF can't track two instances of the same entity, which is why the exception is thrown, so you will need to give EF additional information here to know what to do. EF 无法跟踪同一实体的两个实例,这就是抛出异常的原因,因此您需要在此处向 EF 提供附加信息以了解该怎么做。 This can be complicated in the general case.在一般情况下,这可能很复杂。
For example: if the tracked instance has properties that have been modified in the other instance.例如:如果被跟踪实例的属性在另一个实例中已被修改。
However, assuming that isn't the case, then you can just lookup the instance that is being tracked and use it instead, For example:但是,假设情况并非如此,那么您只需查找正在跟踪的实例并使用它,例如:

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

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM