我想要一個支持類來幫助多對多關係。Linq to SQL:多對多支持類
正如我現在看到的那樣,它可能是一個雙重泛型類,您可以在一個或兩個圍繞關係的實體局部類中定義它。
獲得它允許訪問其他表而不必特別提及關係表應該很容易。然而,添加或從集合中刪除有點棘手。您也可以在關係表中添加一行,並根據所做的操作將其提交或刪除。
這可以通過傳遞到這個泛型類的函數來完成嗎?
像這樣的類是否存在,如果不存在,是否可以完成?
我想要一個支持類來幫助多對多關係。Linq to SQL:多對多支持類
正如我現在看到的那樣,它可能是一個雙重泛型類,您可以在一個或兩個圍繞關係的實體局部類中定義它。
獲得它允許訪問其他表而不必特別提及關係表應該很容易。然而,添加或從集合中刪除有點棘手。您也可以在關係表中添加一行,並根據所做的操作將其提交或刪除。
這可以通過傳遞到這個泛型類的函數來完成嗎?
像這樣的類是否存在,如果不存在,是否可以完成?
您可以創建一個IManyToManySet<TEntity>
接口,該接口可以從您的多個屬性返回並具有ManyToManySet<TSource, TCross, TDestination>
實現以及查詢插入和刪除功能。
的界面看起來可能是這樣:
public interface IManyToManySet<TEntity> : IEnumerable<TEntity>
where TEntity : class
{
int Count { get; }
void Add(TEntity entity);
bool Remove(TEntity entity);
void AddRange(IEnumerable<TEntity> collection);
}
和實現可能是這樣的:
public class ManyToManySet<TSource, TCross, TDestination>
: IManyToManySet<TDestination>, IEnumerable<TDestination>
where TDestination : class
where TSource : class
where TCross : class
{
private TSource source;
private EntitySet<TCross> crossSet;
private Func<TCross, TDestination> destinationSelector;
private Func<TSource, TDestination, TCross> crossFactory;
public ManyToManySet(TSource source,
EntitySet<TCross> crossSet,
Func<TCross, TDestination> destinationSelector,
Func<TSource, TDestination, TCross> crossFactory)
{
this.source = source;
this.crossSet = crossSet;
this.destinationSelector = destinationSelector;
this.crossFactory = crossFactory;
}
public int Count
{
get { return this.crossSet.Count; }
}
public void Add(TDestination entity)
{
var newEntity = this.crossFactory(this.source, entity);
this.crossSet.Add(newEntity);
}
public bool Remove(TDestination entity)
{
var existingEntity = (
from c in this.crossSet
where this.destinationSelector(c) == entity
select c)
.SingleOrDefault();
if (existingEntity != null)
{
return this.crossSet.Remove(existingEntity);
}
return false;
}
public void AddRange(IEnumerable<TDestination> collection)
{
foreach (var entity in collection)
{
this.Add(entity);
}
}
public IEnumerator<TDestination> GetEnumerator()
{
return this.crossSet.Select(this.destinationSelector)
.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
您需要提供幾件事情在此實現:
TSource
實例,該實例指向定義屬性的實體。EntitySet<TCross>
。TCross
轉換爲TDestination
。TSource
和TDestination
創建新的TCross
。翻譯這一個實際的例子(使用Product
和Order
),會給你的Order
實體以下屬性:
private IManyToManySet<Product> products;
public IManyToManySet<Product> Products
{
get
{
if (this.products != null)
{
this.products = new ManyToManySet<Order, OrderProduct, Product>(
this, this.OrderProducts, op => op.Product,
(o, p) => new OrderProduct { Order = o, Product = p });
}
return this.products;
}
}
而下面的屬性在Product
實體:
private IManyToManySet<Order> orders;
public IManyToManySet<Order> Orders
{
get
{
if (this.orders == null)
{
this.orders = new ManyToManySet<Product, OrderProduct, Order>(
this, this.OrderProducts, op => op.Order,
(p, o) => new OrderProduct { Order = o, Product = p });
}
return this.orders;
}
}
IManyToManySet<T>
接口實際上是多餘的,因爲您可以直接返回ManyToMany<TSource, TCross, TDestination>
。然而,該接口隱藏了TSource
和TCross
類型參數,這使得該屬性的用戶可讀性更高。
請注意,此實現具有與LINQ to SQL的EntitySet<T>
相同的加載行爲;當它被使用時,它會將完整的一組對象加載到內存中。就像在集合上使用where
或First
的EntitySet<T>
一樣,仍然從數據庫加載完整的集合。你需要意識到這一點。
不過,LINQ to SQL理解LINQ查詢中的EntitySet<T>
屬性。在LINQ查詢中有一個IManyToManySet<T>
將失敗。
我希望這會有所幫助。
很難(甚至不可能)創建LINQ到SQL,感覺像一些本土的解決方案,因爲這樣的解決方案必須在以下幾個方面工作:
很容易爲第1點做出解決方案。例如,帶有Product
類的模型與Order
具有多對多關係。您可以定義在Order
類以下屬性:
public IEnumerable<Product> Products
{
get { return this.OrderProducts.Select(op => op.Product); }
}
然而,這並不與點2和3的工作,而我們可以做一個普通的集合,它允許插入,LINQ to SQL的將永遠無法翻譯將此屬性用於SQL查詢。例如,下面的LINQ查詢看起來無辜:
var bigOrders =
from order in context.Orders
where order.Products.Any(p => p.Price > 100)
select order;
不幸的是,這個查詢將失敗,因爲LINQ to SQL的不知道如何Products
屬性SQL映射。
如果您本地需要此功能,則應考慮遷移到實體框架(4.0或更高版本)。 EF本身支持這一點。
好的我將在下一個項目中使用EF。但是,讓我們說我不想以有限的方式對待另一個。基本上得到關係另一端的對象列表(例子中的產品),並能夠直接插入,更新和刪除那些會自動創建關係的集合。這可以通過將Order類中的函數傳遞到處理添加的自定義集合類來完成嗎? – 2011-04-12 11:50:54
@Ingó:看到我的第二個答案。我寫了一個可以做到這一點的泛型類的實現。 – Steven 2011-04-12 15:14:33
我有一個小問題是刪除關係,因爲該操作試圖在交叉表中將外鍵清零,而不是僅刪除該行。我發現我可以在關聯上設置一個DeleteOnNull,以確保當從父項目entitySet中移除時該行將被刪除。 – 2011-04-13 14:03:57
當一個計劃聚集在一起時,我喜歡它! – Steven 2011-04-13 14:34:57