我發現無論做了什麼,EF都要求ICollection<T>
公開。我認爲這是因爲當從數據庫加載對象時,映射查找集合屬性,獲取集合,然後調用集合的方法來添加每個子對象。
我想確保添加是通過父對象上的方法完成的,因此創建了一個包裝集合的方法,捕獲添加並將其指向我的首選添加方法。
擴展List
和其他集合類型是不可能的,因爲Add
方法不是虛擬的。一種選擇是擴展Collection
類並覆蓋InsertItem
方法。
我只專注於ICollection<T>
接口的Add
,Remove
和Clear
函數,因爲那些函數可以修改集合。
首先,是我的基本集合包裝器,它實現ICollection<T>
接口 默認行爲是普通集合的默認行爲。但是,調用者可以指定要調用的替代方法Add
。此外,呼叫者可以強制執行Add
,Remove
,Clear
操作,但不允許通過設置null
的替代方法。如果有人試圖使用該方法,則會導致NotSupportedException
被拋出。
拋出一個異常不如一開始就阻止訪問。但是,代碼應該被測試(單元測試),並且會很快發現異常,並進行適當的代碼更改。
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();
}
}
鑑於該基類,我們可以通過兩種方式使用它。例子是使用原始的post對象。
1)創建特定類型的包裝集合(例如,List
) 公共類WrappedListCollection:WrappedCollectionBase,IList的 { 私人列表innerList;
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
}
這可以被用來:
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);
}
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;
}
}
其可以如下使用:
{ 公共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);
}
還有一些其他的方式來調用WrappedCollection
構造 例如,覆蓋增加,但保持撈出清晰爲正常
private WrappedListCollection<Order> _orders = new WrappedListCollection(this.AddOrder, (Order o) => _orders.RemoveFromInnerCollection(o),() => _orders.ClearInnerCollection());
我同意,這將是最好的,如果EF不會要求該集合被公開,但是這個解決方案允許我控制我的收藏的修改。
對於防止訪問集合進行查詢的問題,您可以使用上面的方法2)並將WrappedCollection GetEnumerator
方法設置爲拋出NotSupportedException
。那麼你的方法可以保持原樣。一個整潔的方法可能會暴露包裝的集合。例如:
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;
}
}
然後在GetOrder
方法的調用將成爲
_orders.InnerCollection.Where(x => x.Id == id).Single();
如果我將收集的訪問修飾符設置爲任何東西,但公衆它不是在讀值。從「保護」回「大衆」一個簡單的開關,例如,使得它所有的工作。此外,它似乎也沒有映射簡單的(例如字符串)非公共屬性。 – dommer 2010-11-03 13:34:53
另一種方法是添加一個T4文件並對其進行編輯以顯示集合的IEnumerable的ap屬性,並使默認的ICollection屬性受保護。 –
Michael
2011-05-05 17:39:59