Entity Framework 一对多替换集合的正确方法
Entity Framework proper way to replace collection in one to many
假设一个客户有很多phone个号码,一个phone个号码只有一个客户。
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);
}
}
如果我像这样进行 EF 映射并 运行 它,每次我设置 phone 号码时,它都会创建新的 PhoneNumbers 但不会删除旧的。没有其他实体引用 phone 数字,我什至没有在我的 dbcontext 上公开它,有没有办法告诉 EF Customer
完全拥有 PhoneNumbers
因此如果 phone 号码已从集合中删除,应该删除吗?
我知道有很多方法可以解决这个问题,但这不是一个奇怪的边缘情况,"right" 处理这个问题的方法是什么。
第一个(可选):
我推荐你制作
public ICollection<PhoneNumber> phones {get; private set;}
a virtual
属性,让 Entity Framework 知道它应该延迟加载(即使你没有 延迟加载启用,这是一个很好的做法)。
public virtual ICollection<PhoneNumber> phones {get; private set;}
第二:
在您的PhoneNumber
class上添加反向导航属性(需要 为了实现我在下面给你的解决方案):
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);
}
}
第三(您的问题的可能解决方案):
从 Context 中移除 PhoneNumber
对象,而不是从 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);
}
}
我有完全相同的问题:)
identifying relationships 上的回答解决了我的问题。
注意:您必须加载集合(急切地、显式地或延迟地)以便在设置新值和调用保存之前可以对其进行跟踪。否则你不会替换集合,而只是添加它。
例如:
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();
这将从 'collection table' 中删除以前的集合值,只添加新设置的值。
希望对您有所帮助。
假设一个客户有很多phone个号码,一个phone个号码只有一个客户。
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);
}
}
如果我像这样进行 EF 映射并 运行 它,每次我设置 phone 号码时,它都会创建新的 PhoneNumbers 但不会删除旧的。没有其他实体引用 phone 数字,我什至没有在我的 dbcontext 上公开它,有没有办法告诉 EF Customer
完全拥有 PhoneNumbers
因此如果 phone 号码已从集合中删除,应该删除吗?
我知道有很多方法可以解决这个问题,但这不是一个奇怪的边缘情况,"right" 处理这个问题的方法是什么。
第一个(可选):
我推荐你制作
public ICollection<PhoneNumber> phones {get; private set;}
a virtual
属性,让 Entity Framework 知道它应该延迟加载(即使你没有 延迟加载启用,这是一个很好的做法)。
public virtual ICollection<PhoneNumber> phones {get; private set;}
第二:
在您的PhoneNumber
class上添加反向导航属性(需要 为了实现我在下面给你的解决方案):
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);
}
}
第三(您的问题的可能解决方案):
从 Context 中移除 PhoneNumber
对象,而不是从 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);
}
}
我有完全相同的问题:)
identifying relationships 上的回答解决了我的问题。
注意:您必须加载集合(急切地、显式地或延迟地)以便在设置新值和调用保存之前可以对其进行跟踪。否则你不会替换集合,而只是添加它。
例如:
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();
这将从 'collection table' 中删除以前的集合值,只添加新设置的值。
希望对您有所帮助。