我有这样的场景:我有这些课程:
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;
}
}
有人知道如何实现它吗?
答案 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);
答案 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 希望它会帮助你