繁体   English   中英

Ef代码首先使级联删除方案复杂化

[英]Ef code first complicate cascade delete scenario

我有这样的场景:我有这些课程:

public class A
{
   public int Id {get;set;}
   public virtual ICollection<B> bCollection {get; set; }
}

public class B
{
   public int Id {get;set;}

}

public class C1 : BaseClass1
{
   public int Id{get;set;}
   public virtual B B{get;set;}
}

public class C2 : BaseClass2
{
   public int Id {get;set;}
   public virtual B B {get;set;}
}

...
 public class C100 : BaseClass100
{
   public int Id {get;set;}
   public virtual B B {get;set;}
}

A类具有B类的集合,Ci类具有一个B类和不同的基类 当在A类集合中只有B不能引用它时,我可以删除A类并且所有B集合也被删除(级联删除)。 但是当在A类集合中有B类时Ci引用它我不能删除A类实例...

我的预期行为:

A类将被删除,A类的所有B集合都被删除,如果Ci引用了集合中的某些B,它将在删除结束时为空。(类Ci intances不会被删除!),我也不想迭代抛出我的所有Ci类,看它是否引用了需要删除的B集合。

我不想要这段代码:

MyDbContext db=new MyDbContext();
Hash<int> bCollectionToDelete=GetBCollectionToDeleteHashSet();
var C1_db_collection= db.C1Collection.ToList();
foreach(var c1Item in C1Collection)
{
    if(bCollectionToDelete.Contains(c1Item.refrenceIdToB)
    {
       c1Item.refrenceIdToB=null;
    }
}

 var C2_db_collection= db.C2Collection.ToList();
foreach(var c2Item in C1Collection)
{
    if(bCollectionToDelete.Contains(c2Item.refrenceIdToB)
    {
       c2Item.refrenceIdToB=null;
    }
}

...
 var C100_db_collection= db.C100Collection.ToList();
foreach(var c100Item in C100Collection)
{
    if(bCollectionToDelete.Contains(c100Item.refrenceIdToB)
    {
       c100Item.refrenceIdToB=null;
    }
}

有人知道如何实现吗?

这可能是您编写存储过程来处理级联删除逻辑的情况,并且EF代码只调用“DeleteMyObject”sp然后您的ef代码将需要刷新其上下文以在之后立即重新加载更改。

您将为刷新上下文付出轻微的性能损失,但如果我不得不猜测将逻辑移动到sp,并且在那里执行相互关联的删除的性能增益将抵消必须刷新的小的性能损失。

不确定SP是否适合您,但是您可以在需要时使用它们。

编辑:

存储过程的非常简化的示例,它接受表'MainTable'的主键,然后从3'ChildTables'删除任何相关记录(如果存在)。 你的实际逻辑可能有点复杂:

CREATE PROCEDURE DeleteMyObject @Id INT
as
   BEGIN TRAN
     delete from ChildTable1 WHERE ParentId=@Id
     delete from ChildTable2 WHERE ParentId=@Id
     delete from ChildTable3 WHERE ParentId=@Id
     delete from MainTable WHERE ID=@Id

   COMMIT TRAN

调用未映射到EF模型的SP的示例:

SqlParameter param1 = new SqlParameter(“@ Id”,12345); context.Database.ExecuteSqlCommand(“DeleteMyObject @Id”,param1);

进一步阅读: http//msdn.microsoft.com/en-us/data/gg699321.aspx

而不是在所有C类中搜索,你可以让B去除他自己

通过使用接口

public interface IRemoveB
{
    void RemoveB();
}

public class C1 : BaseClass1, IDeleteB
{
    public int Id { get; set; }
    public virtual B B { get; set; }

    #region IDeleteB Member

    public void RemoveB()
    {
        this.B = null;
    }

    #endregion
}


public class B
{
    public int Id { get; set; }
    public ICollection<IDeleteB>  list{ get; set; }

}
public class A
{
    public int Id { get; set; }
    public virtual ICollection<B> bCollection { get; set; }

    public void prepareForDelete()
    {
        foreach (var item in bCollection)
        {
            foreach (var deref in item.list)
            {
                deref.RemoveB();
            }
        }
    }
}

通过使用代表

public class A
{
    public int Id { get; set; }

    public virtual ICollection<B> bCollection { get; set; }

    public void prepareForDelete()
    {
        foreach (var item in bCollection)
        {
            item.RemoveMe();
        }
    }
}


public class B
{
    public int Id { get; set; }

    public event EventHandler Remove;

    public void RemoveMe()
    {
        EventHandler removeHandler = Remove;
        if (removeHandler != null)
        {
            removeHandler(this, EventArgs.Empty);
        }
    }
}
public class C2 : BaseClass2
{
    public int Id { get; set; }

    private B internB;

    // maybe you need an otherform to set B because of your virtual 
    public B B
    {
        get { return internB; }
        set
        {
            if (internB != value)
                if (internB != null)
                    internB.Remove -= this.RemoveB;
                else if(value != null)
                    value.Remove += this.RemoveB;
            internB = value;
        }
    }

    public void RemoveB(object sender, EventArgs args)
    {
        internB.Remove -= this.RemoveB;
        B = null;

    }
}

编辑:

回答你的问题

You mean thet every ci inherit from the same interface?
对,就是这样。 以下是有关Interface的更多信息

and if yes ICollection<IDeleteB> is stored in the database?
不,它只存在于您的程序中。 可以把它想象成一个临时的1:N参考

and in the delegate example how it is store in the database?
不,它基本上像集合一样思考

如果这只是工作B in A == B in C这不意味着它是相同的实例 B类的

您可以通过添加以下内容为方法OnModelCreating中的每个类Ci设置删除级联的选项为true

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // for each class Ci write the following
    modelBuilder.Entity<Ci>()
            .HasRequired(t=>T.B)
            .WithMany()
            .WillCascadeOnDelete(true);
}

通过这个删除将删除你的Ci如果存在与B类希望它会帮助你

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM