Linq to sql 通过linq到sql删除多对多关系的正确方法?
假设我们有两个具有多对多关系的表:Linq to sql 通过linq到sql删除多对多关系的正确方法?,linq-to-sql,many-to-many,Linq To Sql,Many To Many,假设我们有两个具有多对多关系的表: public class Left{ /**/ } public class Right{ /**/ } public class LeftRight{ /**/ } 以下内容是否足以解开这些记录(忽略存在多个关系或未定义关系的可能性) 还是两个部分都要做?这里需要什么?这里是我为简化此问题而编写的一个“小”扩展方法: public static class EntitySetExtensions { public static void
public class Left{ /**/ }
public class Right{ /**/ }
public class LeftRight{ /**/ }
以下内容是否足以解开这些记录(忽略存在多个关系或未定义关系的可能性)
还是两个部分都要做?这里需要什么?这里是我为简化此问题而编写的一个“小”扩展方法:
public static class EntitySetExtensions
{
public static void UpdateReferences<FK, FKV>(
this EntitySet<FK> refs,
Func<FK, FKV> fkvalue,
Func<FKV, FK> fkmaker,
Action<FK> fkdelete,
IEnumerable<FKV> values)
where FK : class
where FKV : class
{
var fks = refs.Select(fkvalue).ToList();
var added = values.Except(fks);
var removed = fks.Except(values);
foreach (var add in added)
{
refs.Add(fkmaker(add));
}
foreach (var r in removed)
{
var res = refs.Single(x => fkvalue(x) == r);
refs.Remove(res);
fkdelete(res);
}
}
}
公共静态类EntitySetExtensions
{
公共静态void UpdateReferences(
此实体集引用,
Func fkvalue,
Func-fkmaker,
删除行动,
IEnumerable值)
其中FK:类
其中FKV:类
{
var fks=refs.Select(fkvalue.ToList();
增值=除(fks)外的其他值;
移除的var=fks.除外(值);
foreach(添加了变量外接程序)
{
参考添加(fkmaker(添加));
}
foreach(已删除中的var r)
{
var res=参考单(x=>fkvalue(x)==r);
参考文献:移除(res);
删除(res);
}
}
}
它可能会有所改进,但对我来说效果很好:)
例如:
Left entity = ...;
IEnumerable<Right> rights = ...;
entity.LeftRights.UpdateReferences(
x => x.Right, // gets the value
x => new LeftRight { Right = x }, // make reference
x => { x.Right = null; }, // clear references
rights);
左实体=。。。;
IEnumerable rights=。。。;
entity.LeftRights.UpdateReferences(
x=>x.Right,//获取值
x=>newleftright{Right=x},//进行引用
x=>{x.Right=null;},//清除引用
权利);
算法说明:
假设A和B是多对多关系,其中AB是中间表
这将为您提供:
class A { EntitySet<B> Bs {get;} }
class B { EntitySet<A> As {get;} }
class AB { B B {get;} A A {get;} }
class A{EntitySet Bs{get;}
类B{EntitySet为{get;}}
类AB{B{get;}A{get;}
现在有了一个A的对象,它通过AB引用了许多B
我想通过使用表达式来改进这一点,这样我可以更好地“模板化”该方法,但效果相同。举两个例子,使用表达式:
public static class EntitySetExtensions
{
public static void UpdateReferences<FK, FKV>(
this EntitySet<FK> refs,
Expression<Func<FK, FKV>> fkexpr,
IEnumerable<FKV> values)
where FK : class
where FKV : class
{
Func<FK, FKV> fkvalue = fkexpr.Compile();
var fkmaker = MakeMaker(fkexpr);
var fkdelete = MakeDeleter(fkexpr);
var fks = refs.Select(fkvalue).ToList();
var added = values.Except(fks);
var removed = fks.Except(values);
foreach (var add in added)
{
refs.Add(fkmaker(add));
}
foreach (var r in removed)
{
var res = refs.Single(x => fkvalue(x) == r);
refs.Remove(res);
fkdelete(res);
}
}
static Func<FKV, FK> MakeMaker<FKV, FK>(Expression<Func<FK, FKV>> fkexpr)
{
var me = fkexpr.Body as MemberExpression;
var par = Expression.Parameter(typeof(FKV), "fkv");
var maker = Expression.Lambda(
Expression.MemberInit(Expression.New(typeof(FK)),
Expression.Bind(me.Member, par)), par);
var cmaker = maker.Compile() as Func<FKV, FK>;
return cmaker;
}
static Action<FK> MakeDeleter<FK, FKV>(Expression<Func<FK, FKV>> fkexpr)
{
var me = fkexpr.Body as MemberExpression;
var pi = me.Member as PropertyInfo;
var par = Expression.Parameter(typeof(FK), "fk");
var maker = Expression.Lambda(
Expression.Call(par, pi.GetSetMethod(),
Expression.Convert(Expression.Constant(null), typeof(FKV))), par);
var cmaker = maker.Compile() as Action<FK>;
return cmaker;
}
}
公共静态类EntitySetExtensions
{
公共静态void UpdateReferences(
此实体集引用,
表达式fkexpr,
IEnumerable值)
其中FK:类
其中FKV:类
{
Func fkvalue=fkexpr.Compile();
var fkmaker=MakeMaker(fkexpr);
var fkdelete=MakeDeleter(fkexpr);
var fks=refs.Select(fkvalue.ToList();
增值=除(fks)外的其他值;
移除的var=fks.除外(值);
foreach(添加了变量外接程序)
{
参考添加(fkmaker(添加));
}
foreach(已删除中的var r)
{
var res=参考单(x=>fkvalue(x)==r);
参考文献:移除(res);
删除(res);
}
}
静态Func MakeMaker(表达式FKEPR)
{
var me=fkexpr.Body作为MemberExpression;
VaR PAR=表达式参数(Type of(FKV),“FKV”);
var maker=Expression.Lambda(
Expression.MemberInit(Expression.New(typeof(FK)),
表达式.Bind(me.Member,par)),par);
var cmaker=maker.Compile()作为Func;
返回cmaker;
}
静态操作MakeDeleter(表达式fkexpr)
{
var me=fkexpr.Body作为MemberExpression;
var pi=me.Member作为PropertyInfo;
VaR PAR=表达式参数(Type of(FK),FK);
var maker=Expression.Lambda(
Expression.Call(par,pi.GetSetMethod(),
Expression.Convert(Expression.Constant(null)、typeof(FKV))、par);
var cmaker=maker.Compile()作为操作;
返回cmaker;
}
}
现在的用法非常简单!:)
左实体=。。。;
IEnumerable rights=。。。;
entity.LeftRights.UpdateReferences(x=>x.Right,rights);
第一个表达式现在用于建立“关系”。从这里,我可以推断出之前需要的两名代表。现在没有了:)
重要提示:
要使其在Linq2Sql中正常工作,需要在dbml文件中使用“DeleteOnNull=”true“标记中间表中的关联。这将破坏设计器,但仍能正确使用SqlMetal
要破坏设计器,您需要删除这些附加属性。我个人会替换
left.LeftRrights.Remove(relation.First());
与
因为接下来会发生什么似乎更为明显。如果您想知道“.Remove”现在的行为是什么,那么当您在6个月后查看此代码时,您将再次感到疑惑。太好了。你能不能也提供一个算法的描述?哦,xml注释总是很好的!我一直在看这个,你能补充一些关于它用法的信息吗?一个简单的代码片段就足够了。必须将“DeleteOnNull=“True”添加到“AB”关系中,或者添加到何处?我在这两个关系上添加了它,但我的设计器仍然有效,如果我重新创建表,这些关系会消失吗?(拖放等)。谢谢
Left entity = ...;
IEnumerable<Right> rights = ...;
entity.LeftRights.UpdateReferences(x => x.Right, rights);
left.LeftRrights.Remove(relation.First());
Db.LeftRights.DeleteAllOnSubmit(relation)