Linq to sql Linq到SQL:多对多支持类
我想要一个支持课程来帮助处理多对多关系 正如我现在看到的,它可以是一个双泛型类,您可以在围绕关系的一个或两个实体分部类中定义 让它允许访问另一个表而不必特别提到关系表应该很容易。然而,从集合中添加或删除有点棘手。您还需要在关系表中添加一行,并根据所做的操作提交或删除该行 这可以通过传递给这个泛型类的函数来完成吗 这样的类是否存在?如果不存在,它是否可以实现?很难(甚至不可能)在LINQ to SQL中创建一个感觉像本机的解决方案,因为这样的解决方案必须以以下方式工作:Linq to sql Linq到SQL:多对多支持类,linq-to-sql,generics,many-to-many,generic-list,Linq To Sql,Generics,Many To Many,Generic List,我想要一个支持课程来帮助处理多对多关系 正如我现在看到的,它可以是一个双泛型类,您可以在围绕关系的一个或两个实体分部类中定义 让它允许访问另一个表而不必特别提到关系表应该很容易。然而,从集合中添加或删除有点棘手。您还需要在关系表中添加一行,并根据所做的操作提交或删除该行 这可以通过传递给这个泛型类的函数来完成吗 这样的类是否存在?如果不存在,它是否可以实现?很难(甚至不可能)在LINQ to SQL中创建一个感觉像本机的解决方案,因为这样的解决方案必须以以下方式工作: 多集合应建模为其他多实体上
产品
类的模型为例,该类与订单
具有多对多关系。您可以在Order
类上定义以下属性:
public IEnumerable<Product> Products
{
get { return this.OrderProducts.Select(op => op.Product); }
}
不幸的是,此查询将失败,因为LINQ to SQL不知道如何将产品
属性映射到SQL
当你想这个特性时,你应该考虑迁移到实体框架(4或UP)。EF本机支持这一点。
很难(甚至不可能)在LINQ to SQL中创建一个感觉像本机的解决方案,因为这样的解决方案必须以以下方式工作:产品
类的模型为例,该类与订单
具有多对多关系。您可以在Order
类上定义以下属性:
public IEnumerable<Product> Products
{
get { return this.OrderProducts.Select(op => op.Product); }
}
不幸的是,此查询将失败,因为LINQ to SQL不知道如何将产品
属性映射到SQL
当你想这个特性时,你应该考虑迁移到实体框架(4或UP)。EF本机支持此功能。
您可以创建一个IManyToManySet
接口,该接口可以从多对多属性返回,并具有带有查询插入和删除功能的ManyToManySet
实现
界面可能如下所示:
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();
}
}
以及产品
实体中的以下属性:
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;
}
}
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订单;
公共IManyToManySet命令
{
得到
{
if(this.orders==null)
{
this.orders=new ManyToManySet(
this,this.OrderProducts,op=>op.Order,
(p,o)=>neworderproduct{Order=o,Product=p});
}
退回此订单;
}
}
实际上,IManyToManySet
接口是多余的,因为您可以直接返回一个manytomy
。但是,该接口隐藏了TSource
和TCross
类型参数,这使得该属性的用户更易于阅读
请注意,此实现具有与LINQ to SQL的EntitySet
相同的加载行为;当使用它时,它会在内存中加载完整的对象集。就像使用实体集
在集合上使用where
或First
一样,仍然从数据库加载完整的集合。你需要意识到这一点
然而,重要的区别在于LINQtoSQL理解LINQ查询中的EntitySet
属性。在LINQ查询中使用IManyToManySet
,将会失败得很惨
我希望这会有所帮助。您可以创建一个
IManyToManySet
接口,该接口可以从多对多属性返回,并具有带有查询插入和删除功能的ManyToManySet
实现
界面可能如下所示:
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();
}
}
以及产品
实体中的以下属性:
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;
}
}
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订单;
公共IManyToManySet命令
{
得到
{
if(this.orders==null)
{
this.orders=new ManyToManySet(
this,this.OrderProducts,op=>op.Order,
(p,o)=>neworderproduct{Order=o,Product=p});
}
退回此订单;
}
}
实际上,IManyToManySet
接口是多余的,因为您可以直接返回一个manytomy
。但是,该接口隐藏了TSource
和TCross
类型参数,这使得该属性的用户更易于阅读
请注意,此实现具有与LINQ to SQL的EntitySet
相同的加载行为;当使用它时,它会在内存中加载完整的对象集。就像使用实体集
在集合上使用where
或First
一样,仍然从数据库加载完整的集合。你需要意识到这一点
然而,重要的区别在于LINQtoSQL理解LINQ查询中的EntitySet
属性。在LINQ查询中使用IManyToManySet
,将会失败得很惨
我希望这有帮助。好的,我将在下一个项目中使用EF。但我想说的是,我在某种程度上不想成为另一个。基本上,您可以获得关系另一端的对象列表(示例中的产品),并能够直接插入、更新和删除到将自动创建关系的集合。这可以通过将Order类中的函数传递到自定义集合中来实现吗