每次我想更新我的记录时,都会收到以下错误:
“无法跟踪实体类型'用户'的实例,因为另一个实例 已经跟踪了具有相同密钥的此类型的实例。什么时候 为大多数密钥类型添加新实体的唯一临时密钥值 如果没有设置密钥,则将创建(即,如果分配了密钥属性) 其类型的默认值)。如果您明确设置密钥 新实体的值,确保它们不会与现有实体发生冲突 为其他新实体生成的实体或临时值。什么时候 附加现有实体,确保只有一个实体实例 给定的键值附加到上下文中。“
这是我的代码:
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,它失败,出现同样的错误
这让我疯了,我无法弄清楚!!!
答案 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);
}