dom*_*mer 6 entity-framework icollection code-first entity-framework-4
我的具有一对多映射的域类通常采用以下形式(未经测试的代码):
public Customer Customer
{
// Public methods.
public Order AddOrder(Order order)
{
_orders.Add(order);
}
public Order GetOrder(long id)
{
return _orders.Where(x => x.Id).Single();
}
// etc.
// Private fields.
private ICollection<Order> _orders = new List<Order>();
}
Run Code Online (Sandbox Code Playgroud)
我在处理一对多关系时看到的EF4代码示例公开了一个公共ICollection.
有没有办法通过暴露它们来持久化和恢复我的收藏?如果没有,似乎我的域对象将被设计为满足ORM的要求,这似乎违背了努力的精神.公开ICollection(使用它的Add等方法)似乎并不特别干净,也不是我的默认方法.
更新
发现这篇文章表明它在5月份是不可能的.当然,微软的海报确实表示他们"正在强烈考虑实施"它(我希望如此)而且我们已经半年了,所以也许有一些进步?
我发现无论做什么,EF 都要求ICollection<T>公开。我认为这是因为当从数据库加载对象时,映射会查找集合属性,获取集合,然后调用Add集合的方法来添加每个子对象。
我想确保添加是通过父对象上的方法完成的,因此创建了一个包装集合、捕获添加并将其定向到我首选的添加方法的解决方案。
扩展 aList和其他集合类型是不可能的,因为该Add方法不是虚拟的。一种选择是扩展Collection类并重写该InsertItem方法。
我只关注接口的Add、Remove和Clear函数,ICollection<T>因为这些是可以修改集合的函数。
首先,是我的基本集合包装器,它实现了ICollection<T>接口。默认行为是普通集合的行为。但是,调用者可以指定Add要调用的替代方法。此外,调用者可以通过设置 的替代项来强制不允许Add, Remove,操作。如果有人尝试使用该方法,则会导致抛出异常。ClearnullNotSupportedException
抛出异常不如从一开始就阻止访问好。但是,应该对代码进行测试(单元测试),并且会很快发现异常并进行适当的代码更改。
public abstract class WrappedCollectionBase<T> : ICollection<T>
{
private ICollection<T> InnerCollection { get { return GetWrappedCollection(); } }
private Action<T> addItemFunction;
private Func<T, bool> removeItemFunction;
private Action clearFunction;
/// <summary>
/// Default behaviour is to be like a normal collection
/// </summary>
public WrappedCollectionBase()
{
this.addItemFunction = this.AddToInnerCollection;
this.removeItemFunction = this.RemoveFromInnerCollection;
this.clearFunction = this.ClearInnerCollection;
}
public WrappedCollectionBase(Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction) : this()
{
this.addItemFunction = addItemFunction;
this.removeItemFunction = removeItemFunction;
this.clearFunction = clearFunction;
}
protected abstract ICollection<T> GetWrappedCollection();
public void Add(T item)
{
if (this.addItemFunction != null)
{
this.addItemFunction(item);
}
else
{
throw new NotSupportedException("Direct addition to this collection is not permitted");
}
}
public void AddToInnerCollection(T item)
{
this.InnerCollection.Add(item);
}
public bool Remove(T item)
{
if (removeItemFunction != null)
{
return removeItemFunction(item);
}
else
{
throw new NotSupportedException("Direct removal from this collection is not permitted");
}
}
public bool RemoveFromInnerCollection(T item)
{
return this.InnerCollection.Remove(item);
}
public void Clear()
{
if (this.clearFunction != null)
{
this.clearFunction();
}
else
{
throw new NotSupportedException("Clearing of this collection is not permitted");
}
}
public void ClearInnerCollection()
{
this.InnerCollection.Clear();
}
public bool Contains(T item)
{
return InnerCollection.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
InnerCollection.CopyTo(array, arrayIndex);
}
public int Count
{
get { return InnerCollection.Count; }
}
public bool IsReadOnly
{
get { return ((ICollection<T>)this.InnerCollection).IsReadOnly; }
}
public IEnumerator<T> GetEnumerator()
{
return InnerCollection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return InnerCollection.GetEnumerator();
}
}
Run Code Online (Sandbox Code Playgroud)
鉴于该基类,我们可以通过两种方式使用它。示例是使用原始的 post 对象。
1) 创建特定类型的包装集合(例如List) public class WrappedListCollection : WrappedCollectionBase, IList { private List insideList;
public WrappedListCollection(Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
: base(addItemFunction, removeItemFunction, clearFunction)
{
this.innerList = new List<T>();
}
protected override ICollection<T> GetWrappedCollection()
{
return this.innerList;
}
<...snip....> // fill in implementation of IList if important or don't implement IList
}
Run Code Online (Sandbox Code Playgroud)
然后可以使用:
public Customer Customer
{
public ICollection<Order> Orders {get { return _orders; } }
// Public methods.
public void AddOrder(Order order)
{
_orders.AddToInnerCollection(order);
}
// Private fields.
private WrappedListCollection<Order> _orders = new WrappedListCollection<Order>(this.AddOrder, null, null);
}
Run Code Online (Sandbox Code Playgroud)
2)给出一个要包装的集合
public class WrappedCollection<T> : WrappedCollectionBase<T>
{
private ICollection<T> wrappedCollection;
public WrappedCollection(ICollection<T> collectionToWrap, Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
: base(addItemFunction, removeItemFunction, clearFunction)
{
this.wrappedCollection = collectionToWrap;
}
protected override ICollection<T> GetWrappedCollection()
{
return this.wrappedCollection;
}
}
Run Code Online (Sandbox Code Playgroud)
可以如下使用:
{ 公共 ICollection 订单 {get { return _wrappedOrders; } } // 公共方法。
public void AddOrder(Order order)
{
_orders.Add(order);
}
// Private fields.
private ICollection<Order> _orders = new List<Order>();
private WrappedCollection<Order> _wrappedOrders = new WrappedCollection<Order>(_orders, this.AddOrder, null, null);
}
Run Code Online (Sandbox Code Playgroud)
还有一些其他方法可以调用WrappedCollection构造函数例如,覆盖 add 但保持删除和清除正常
private WrappedListCollection<Order> _orders = new WrappedListCollection(this.AddOrder, (Order o) => _orders.RemoveFromInnerCollection(o), () => _orders.ClearInnerCollection());
Run Code Online (Sandbox Code Playgroud)
我同意如果 EF 不要求集合公开是最好的,但此解决方案允许我控制集合的修改。
对于阻止访问集合进行查询的问题,您可以使用上面的方法 2) 并将 WrappedCollectionGetEnumerator方法设置为抛出NotSupportedException. 然后你的GetOrder方法就可以保持原样。然而,更简洁的方法可能是公开包装的集合。例如:
public class WrappedCollection<T> : WrappedCollectionBase<T>
{
public ICollection<T> InnerCollection { get; private set; }
public WrappedCollection(ICollection<T> collectionToWrap, Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
: base(addItemFunction, removeItemFunction, clearFunction)
{
this.InnerCollection = collectionToWrap;
}
protected override ICollection<T> GetWrappedCollection()
{
return this.InnerCollection;
}
}
Run Code Online (Sandbox Code Playgroud)
那么方法中的调用GetOrder就会变成
_orders.InnerCollection.Where(x => x.Id == id).Single();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1073 次 |
| 最近记录: |