Cada vez que quiero actualizar mi registro, obtengo el siguiente error:
"La instancia del tipo de entidad 'Usuario' no se puede rastrear porque ya se está rastreando otra instancia de este tipo con la misma clave. Al agregar nuevas entidades, para la mayoría de los tipos de clave se creará un valor de clave temporal único si no se establece una clave ( es decir, si a la propiedad clave se le asigna el valor predeterminado para su tipo). Si está configurando explícitamente valores clave para nuevas entidades, asegúrese de que no coincidan con entidades existentes o valores temporales generados para otras entidades nuevas. Al vincular entidades existentes, asegúrese de que solo una instancia de entidad con un valor clave dado se adjunta al contexto ".
Aquí está mi código:
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();
}
Las clases relevantes:
Usuario:
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; }
}
Recipiente:
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; }
}
Métodos de contacto:
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; }
}
Este problema ocurre cuando quiero actualizar un destinatario y es otro usuario que realiza la actualización. Entonces, digamos que el usuario abcd hizo la última actualización, pero ahora el usuario zyx actualiza el registro. Por lo tanto, Recipeint.LastUpdatedBy está configurado para el usuario de sesión actual. Cuando hago eso, me sale el error anterior. No puedo averiguar cómo ir más allá de esto.
Una pequeña nota: si agrego esto:
context.Entry(myRecipient.LastModifiedBy).State = EntityState.Unchanged;
en el if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID)
Enunciado, y digamos que el usuario lastmodifiedby está configurado como usuario abc. Ahora el Usuario asfg actualiza este destinatario por primera vez, pasa, y LastModifiedBy se configurará como usuario asfg, pero digamos que el usuario abc vuelve y cambia el destinatario nuevamente, por lo que lastmodifiedby vuelve a abc, falla, con el mismo error .
Esto me está volviendo loco y no puedo entenderlo!
Recibí la respuesta a esto de Arthur Vickers en Microsoft . Yo quería compartir.
El código que establece la propiedad de navegación dbRecipient.LastModifiedBy
lo establece en una instancia de entidad que no está siendo rastreada por el contexto. Parece que, en este caso, el contexto ya está rastreando otra instancia para esta misma entidad, presumiblemente porque fue traída por la consulta a través de la inclusión de la navegación CreatedBy
.
EF no puede rastrear dos instancias de la misma entidad, por lo que se lanza la excepción, por lo que deberá proporcionar aquí información adicional de EF para saber qué hacer. Esto puede ser complicado en el caso general.
Por ejemplo: si la instancia rastreada tiene propiedades que se han modificado en la otra instancia.
Sin embargo, asumiendo que ese no es el caso, entonces puede buscar la instancia que se está rastreando y usarla en su lugar, por ejemplo:
if (dbRecipient.LastModifiedBy.UserGUID != myRecipient.LastModifiedBy.UserGUID)
{
dbRecipient.LastModifiedBy = test.Set<User>().Find(myRecipient.LastModifiedBy.UserGUID);
}