c# - tutorial - Entity Framework forma adecuada de reemplazar la colección de uno a muchos
que es code first entity framework (2)
Supongamos que un cliente tiene muchos números de teléfono y un número de teléfono tiene solo un cliente.
public class PhoneNumber : IValueObject {
public string Number {get; set;}
public string Type {get; set;}
}
public class Customer : IEntity {
public ICollection<PhoneNumber> phones {get; private set;} //ew at no encapsulated collection support
public void SetPhones(params PhoneNumber[] phones) {
this.phones.Clear();
this.phones.AddRange(phones);
}
}
Si hago un mapa de EF como este y lo ejecuto, cada vez que establezco números de teléfono creará nuevos números de teléfono pero no eliminará los antiguos. No hay otras entidades que hagan referencia a números telefónicos, ni siquiera lo expongo en mi contexto actual. ¿Hay alguna forma de decirle a EF que el Customer
posee Números Telefónicos por completo y, por lo tanto, si los números telefónicos fueron eliminados de la colección, deberían eliminarse?
Me doy cuenta de que hay una docena de formas de resolver este problema, pero este no es un caso extraño, ¿cuál es la forma "correcta" de manejar esto?
Primero (opcional):
Te recomiendo que hagas
public ICollection<PhoneNumber> phones {get; private set;}
una propiedad virtual
, para que el Entity Framework sepa que debe estar cargada de manera diferida (incluso si no tiene habilitada la Carga diferida, es una buena práctica).
public virtual ICollection<PhoneNumber> phones {get; private set;}
Segundo :
Agregue una propiedad de navegación inversa en su clase PhoneNumber
(será necesaria para lograr la solución que le doy a continuación):
public class PhoneNumber : IValueObject {
public string Number {get; set;}
public string Type {get; set;}
public virtual Customer {get; set;}
}
public class Customer : IEntity {
public ICollection<PhoneNumber> phones {get; private set;} //ew at no encapsulated collection support
public void SetPhones(params PhoneNumber[] phones) {
this.phones.Clear();
this.phones.AddRange(phones);
}
}
Tercero (Posible solución para su problema):
Elimine los objetos PhoneNumber
del Contexto en lugar de hacerlo desde el Customer
:
public ICollection<PhoneNumber> phones {get; private set;} //ew at no encapsulated collection support
public void SetPhones(params PhoneNumber[] phones) {
Context.PhoneNumbers.RemoveRange(this.phones);
this.phones.AddRange(phones);
}
}
Tenía exactamente la misma pregunta :)
Esta respuesta sobre la identificación de las relaciones resolvió mi problema.
Nota: Debe cargar la colección (ansiosa, explícita o perezosamente) para poder rastrearla antes de establecer los nuevos valores y llamar a guardar. De lo contrario, no reemplazarás la colección, sino que solo agregarás a ella.
Por ejemplo:
var entity = unitOfWork.EntityRepository.GetById(model.Id);
// I have something like this to load collection because
// I don''t have the collection''s entities exposed to the context
unitOfWork.EntityRepository.LoadCollection(entity, e => e.CollectionProperty);
entity.CollectionProperty = newCollectionValuesList;
unitOfWork.Save();
Esto eliminará los valores de recopilación anteriores de la ''tabla de recopilación'' y solo agregará los valores recién establecidos.
Espero que ayude.