zam*_*6ak 18 c# entity-framework readonly-collection ef-code-first
考虑一个客户,公司,员工等具有ContactInfo属性的域,该属性又包含一组地址,电话,电子邮件等等......
这是我的缩写ContactInfo:
public class ContactInfo : Entity<int>
{
public ContactInfo()
{
Addresses = new HashSet<Address>();
}
public virtual ISet<Address> 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);
}
}
Run Code Online (Sandbox Code Playgroud)
一些注释(我不是100%确定这些是EF"最佳实践"):
ISet
为了确保每个联系人没有重复的地址AddAddress
方法我可以确保总有最多1个主要地址....我希望(如果可能的话)阻止通过ContactInfo.Addresses.Add()
方法添加地址并强制使用ContactInfo.AddAddress(Address address)
...
我正在考虑通过实现这一组地址,ReadOnlyCollection
但这是否适用于实体框架(v5)?
我该怎么做?
Pat*_*der 14
Edo van Asseldonk建议的另一个选项是创建一个从Collection继承其行为的自定义集合.
您必须为ISet制作自己的实现,但原理是相同的.
通过隐藏任何修改列表并将其标记为过时的方法,您可以有效地获得ReadOnlyCollection,但是当它取消装箱为Collection时,EF仍然可以修改它.在我的版本中,我为List添加了一个隐式运算符转换,因此我们不必在添加项时取消收集集合:
var list = ListProperty.ToList();
list.Add(entity)
ListProperty = list;
Run Code Online (Sandbox Code Playgroud)
哪里
public virtual EntityCollection<MyEntity> ListProperty { get; protected set; }
Run Code Online (Sandbox Code Playgroud)
这是EntityCollection:
public class EntityCollection<T> : Collection<T>
{
[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<T>(List<T> source)
{
var target = new EntityCollection<T>();
foreach (var item in source)
((Collection<T>) target).Add(item); // unbox
return target;
}
}
Run Code Online (Sandbox Code Playgroud)
这样您仍然可以像往常一样运行Linq,但在尝试修改Collection属性时会得到正确的使用警告.将它解压缩到集合将是唯一的方法:
((Collection<MyEntity>)ListProperty).Add(entity);
Run Code Online (Sandbox Code Playgroud)
一种方法是保护 ICollection 属性并创建 IEnumerable 的新属性,该属性仅返回 ICollection 属性的列表。
这样做的缺点是您无法通过 ContactInfo 查询地址,例如获取居住在该城市的所有联系信息。
这不可能!:
from c in ContactInfos
where c.Addresses.Contains(x => x.City == "New York")
select c
Run Code Online (Sandbox Code Playgroud)
代码:
public class ContactInfo : Entity<int>
{
public ContactInfo()
{
Addresses = new HashSet<Address>();
}
protected virtual ISet<Address> AddressesCollection { get ; private set; }
public IEnumerable<Address> 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);
}
}
Run Code Online (Sandbox Code Playgroud)