entity framework只读集合

考虑一个客户,公司,员工等具有ContactInfo属性的域,该属性又包含一组地址,电话,电子邮件等等……

这是我的缩写ContactInfo:

public class ContactInfo : Entity { public ContactInfo() { Addresses = new HashSet
(); } public virtual ISet
Addresses { get ; private set; } public Address PrimaryAddress { get { return Addresses.FirstOrDefault(a => a.IsPrimary); } } public bool AddAddress(Address address) { // insure there is only one primary address in collection if (address.IsPrimary) { if (PrimaryAddress != null) { PrimaryAddress.IsPrimary = false; } } else { // make sure the only address in collection is primary if (!Addresses.Any()) { address.IsPrimary = true; } } return Addresses.Add(address); } }

一些注释(我不是100%确定这些是EF“最佳实践”):

  • Address(es)的集合是虚拟的,允许延迟加载
  • 私人二手集合禁止收集更换
  • 集合是一个ISet以确保每个联系人没有重复的地址
  • 使用AddAddress方法我可以确保总是最多1个地址是主要的….

我希望(如果可能的话)阻止通过ContactInfo.Addresses.Add()方法添加地址并强制使用ContactInfo.AddAddress(Address address)

我正在考虑通过ReadOnlyCollection公开地址集,但这是否适用于Entity Framework(v5)?

我怎么会这样呢?

一种方法是保护ICollection属性并创建IEnumerable的新属性,该属性只返回ICollection属性的列表。

这样做的缺点是您无法通过ContactInfo查询地址,例如获取此城市中的所有contactinfo。

这是不可能的!:

 from c in ContactInfos where c.Addresses.Contains(x => x.City == "New York") select c 

码:

 public class ContactInfo : Entity { public ContactInfo() { Addresses = new HashSet
(); } protected virtual ISet
AddressesCollection { get ; private set; } public IEnumerable
Addresses { get { return AddressesCollection; }} public Address PrimaryAddress { get { return Addresses.FirstOrDefault(a => a.IsPrimary); } } public bool AddAddress(Address address) { // insure there is only one primary address in collection if (address.IsPrimary) { if (PrimaryAddress != null) { PrimaryAddress.IsPrimary = false; } } else { // make sure the only address in collection is primary if (!Addresses.Any()) { address.IsPrimary = true; } } return Addresses.Add(address); } }

Edo van Asseldonk建议的另一个选项是创建一个自定义集合,从Collectioninheritance其行为。

您必须为ISet制作自己的实现,但原则是相同的。

通过隐藏修改列表并将其标记为过时的任何方法,您可以有效地获得ReadOnlyCollection,但是当它取消装箱为Collection时,EF仍然可以修改它。 在我的版本中,我为List添加了一个隐式运算符转换,因此我们不必在添加项时取消收集集合:

 var list = ListProperty.ToList(); list.Add(entity) ListProperty = list; 

哪里

 public virtual EntityCollection ListProperty { get; protected set; } 

这是EntityCollection:

 public class EntityCollection : Collection { [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] public new void Add(T item) { } [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] public new void Clear() { } [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] public new void Insert(int index, T item) { } [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] public new void Remove(T item) { } [Obsolete("Unboxing this collection is only allowed in the declarating class.", true)] public new void RemoveAt(int index) { } public static implicit operator EntityCollection(List source) { var target = new EntityCollection(); foreach (var item in source) ((Collection) target).Add(item); // unbox return target; } } 

这样您仍然可以像往常一样运行Linq,但在尝试修改Collection属性时会得到正确的使用警告。 将它解压缩到集合将是唯一的方法:

 ((Collection)ListProperty).Add(entity);