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

时间:2014-01-27 10:53:13

标签: c# entity-framework cascade

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

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;
    }
}

有人知道如何实现它吗?

3 个答案:

答案 0 :(得分:3)

这可能是您编写存储过程来处理级联删除逻辑的情况,而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

答案 1 :(得分:0)

不是在所有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?
对,就是这样。 Here are more information about Interface

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

and in the delegate example how it is store in the database?
不,它与集合

基本相同

并且仅当B in A == B in C表示它与B类instance相同时才有效

答案 2 :(得分:-2)

您可以通过添加以下内容在方法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);
}

如果存在B类,删除将删除您的Ci 希望它会帮助你