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

  • 通过“fkvalue”从A.Bs获取所有B
  • 获取添加的内容
  • 获取已删除的内容
  • 添加所有新的,并通过“fkmaker”构建AB
  • 删除所有已删除的
  • (可选)通过“fkdelete”删除其他引用对象

  • 我想通过使用表达式来改进这一点,这样我可以更好地“模板化”该方法,但效果相同。

    举两个例子,使用表达式:

    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)