我意識到答案是一歲,但我覺得它不完整。在我看來,使用自引用表來表示任意深度。
例如,請考慮以下結構:
/*
* earth
* europe
* germany
* ireland
* belfast
* dublin
* south america
* brazil
* rio de janeiro
* chile
* argentina
*
*/
答案沒有解決如何刪除地球,還是歐洲,從結構上。
我提交下面的代碼作爲替代(修改Slauma提供的答案,誰順利做了一個好工作)。
在MyContext類,添加以下方法:
public void DeleteMyEntity(MyEntity entity)
{
var target = MyEntities
.Include(x => x.Children)
.FirstOrDefault(x => x.Id == entity.Id);
RecursiveDelete(target);
SaveChanges();
}
private void RecursiveDelete(MyEntity parent)
{
if (parent.Children != null)
{
var children = MyEntities
.Include(x => x.Children)
.Where(x => x.ParentId == parent.Id);
foreach (var child in children)
{
RecursiveDelete(child);
}
}
MyEntities.Remove(parent);
}
我使用的代碼先用下面的類填充數據:
public class TestObjectGraph
{
public MyEntity RootEntity()
{
var root = new MyEntity
{
Name = "Earth",
Children =
new List<MyEntity>
{
new MyEntity
{
Name = "Europe",
Children =
new List<MyEntity>
{
new MyEntity {Name = "Germany"},
new MyEntity
{
Name = "Ireland",
Children =
new List<MyEntity>
{
new MyEntity {Name = "Dublin"},
new MyEntity {Name = "Belfast"}
}
}
}
},
new MyEntity
{
Name = "South America",
Children =
new List<MyEntity>
{
new MyEntity
{
Name = "Brazil",
Children = new List<MyEntity>
{
new MyEntity {Name = "Rio de Janeiro"}
}
},
new MyEntity {Name = "Chile"},
new MyEntity {Name = "Argentina"}
}
}
}
};
return root;
}
}
我保存到我的數據庫具有以下代碼:
ctx.MyEntities.Add(new TestObjectGraph().RootEntity());
然後調用這樣的刪除:
using (var ctx = new MyContext())
{
var parent = ctx.MyEntities
.Include(e => e.Children)
.FirstOrDefault();
var deleteme = parent.Children.First();
ctx.DeleteMyEntity(deleteme);
}
導致我的數據庫現在有像這樣的結構:
/*
* earth
* south america
* brazil
* rio de janeiro
* chile
* argentina
*
*/
,其中歐洲和所有的孩子都被刪除。
在上面,我指定了根節點的第一個孩子,爲了演示如何使用我的代碼,您可以遞歸地從層次結構中的任何位置刪除一個節點及其所有子節點。
,如果你想測試刪除everyting,你可以簡單地修改這樣的行:你的樹要
ctx.DeleteMyEntity(parent);
或任何節點。
很明顯,我不會得到賞金,但我希望我的帖子將幫助別人尋找一個任意深度的自引用實體有效的解決方案。
下面是完整的源代碼,這是從選定的答案Slauma的代碼修改後的版本:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
namespace EFSelfReference
{
public class MyEntity
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public MyEntity Parent { get; set; }
public ICollection<MyEntity> Children { get; set; }
}
public class MyContext : DbContext
{
public DbSet<MyEntity> MyEntities { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>()
.HasOptional(e => e.Parent)
.WithMany(e => e.Children)
.HasForeignKey(e => e.ParentId);
}
public void DeleteMyEntity(MyEntity entity)
{
var target = MyEntities
.Include(x => x.Children)
.FirstOrDefault(x => x.Id == entity.Id);
RecursiveDelete(target);
SaveChanges();
}
private void RecursiveDelete(MyEntity parent)
{
if (parent.Children != null)
{
var children = MyEntities
.Include(x => x.Children)
.Where(x => x.ParentId == parent.Id);
foreach (var child in children)
{
RecursiveDelete(child);
}
}
MyEntities.Remove(parent);
}
}
public class TestObjectGraph
{
public MyEntity RootEntity()
{
var root = new MyEntity
{
Name = "Earth",
Children =
new List<MyEntity>
{
new MyEntity
{
Name = "Europe",
Children =
new List<MyEntity>
{
new MyEntity {Name = "Germany"},
new MyEntity
{
Name = "Ireland",
Children =
new List<MyEntity>
{
new MyEntity {Name = "Dublin"},
new MyEntity {Name = "Belfast"}
}
}
}
},
new MyEntity
{
Name = "South America",
Children =
new List<MyEntity>
{
new MyEntity
{
Name = "Brazil",
Children = new List<MyEntity>
{
new MyEntity {Name = "Rio de Janeiro"}
}
},
new MyEntity {Name = "Chile"},
new MyEntity {Name = "Argentina"}
}
}
}
};
return root;
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer<MyContext>(
new DropCreateDatabaseAlways<MyContext>());
using (var ctx = new MyContext())
{
ctx.Database.Initialize(false);
ctx.MyEntities.Add(new TestObjectGraph().RootEntity());
ctx.SaveChanges();
}
using (var ctx = new MyContext())
{
var parent = ctx.MyEntities
.Include(e => e.Children)
.FirstOrDefault();
var deleteme = parent.Children.First();
ctx.DeleteMyEntity(deleteme);
}
Console.WriteLine("Completed....");
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}
你可以利用級聯刪除嗎?如果您使用的代碼先遷移,你可以設置= TRUE在創建表的級聯,否則你可能必須通過另一個遷移或通過數據庫進行更新。 我想EF會處理它,如果它能夠級聯。 – 2013-05-09 14:19:14
好主意。我們的數據庫管理員不希望爲整個數據庫啓用級聯,但是我們可以在此FK參考中做到這一點。這正是我剛剛與DBA討論的內容。 :)儘管我仍在尋找其他建議/想法,可能在EF相關代碼的範圍內。 – Kon 2013-05-09 14:22:22
更新:無法在刪除表中的自引用中添加級聯到FK,因爲週期誤差。 – Kon 2013-05-09 21:33:15