我想要一个支持类来帮助多对多关系。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