使用EF Core操作层次结构数据
前言
以前我們存儲層次結構常用Id+ParentId的方式,例如:
| 1 | null | 總公司 | 
| 2 | 1 | 分公司1 | 
| 3 | 1 | 分公司2 | 
| 4 | 2 | 部門A | 
| 5 | 4 | 小組X | 
| 6 | 4 | 小組Y | 
這種方式查詢效率不高,比如查詢分公司1下的所有小組,必須使用遞歸。
針對這個問題,如果你是使用Sql Server,可以嘗試一下HierarchyId。
HierarchyId
HierarchyId是一種長度可變的Sql Server數據類型,它能存儲帶有層次結構的數據。
HierarchyId數據類型的值可以直接表示樹層次結構中的位置,例如:
| / | 總公司 | 
| /1/ | 分公司1 | 
| /2/ | 分公司2 | 
| /1/1/ | 部門A | 
| /1/1/1/ | 小組X | 
| /1/1/2/ | 小組Y | 
HierarchyId可以使用下列函數:
GetAncestor :取得第n個祖先
GetDescendant :取得第n個子節點
GetLevel :取得級別
GetRoot :取得根
Parse :將字符串轉換為HierarchyId
ToString :將HierarchyId轉換為字符串,與parse正好相反
比如,查詢分公司1下的所有小組,可以使用下列語句:
select?*?from?t?where?[Id].GetLevel()?=?3?AND?[Id].GetAncestor(2)?=?'/1/'HierarchyId數據類型詳情請參看官方文檔:https://docs.microsoft.com/zh-cn/sql/relational-databases/hierarchical-data-sql-server?view=sql-server-ver15
代碼示例
下面,我們通過一個示例,演示如何使用Entity Framework Core操作HierarchyId數據類型。
建表
執行下列Sql,在數據庫中建表:
create?table?Organizations(Id?hierarchyid?primary?key,Name?nvarchar(50) );?創建項目
創建控制臺應用程序,然后引用nuget包EntityFrameworkCore.SqlServer.HierarchyId。
定義數據模型
新建Organization.cs,代碼如下:
public?class?Organization {public?HierarchyId?Id??{?get;?set;?}public?string?Name?{?get;?set;?} }注意,Id的類型是HierarchyId。
新建DemoContext.cs,代碼如下:
public?class?DemoContext?:?DbContext {public?DbSet<Organization>?Organizations?{?get;?set;?}protected?override?void?OnConfiguring(DbContextOptionsBuilder?optionsBuilder){string?connectionString?=?"...";optionsBuilder.UseSqlServer(connectionString,?config?=>?config.UseHierarchyId());} }使用config.UseHierarchyId()開啟HierarchyId映射。
增刪改查
現在,我們可以對HierarchyId數據類型進行操作了。
代碼如下:
//增 using?(var?db?=?new?DemoContext()) {db.Organizations.AddRange(new?Organization?{?Id=?HierarchyId.Parse("/"),?Name=?"總公司"?},new?Organization?{?Id?=?HierarchyId.Parse("/1/"),?Name?=?"分公司1"?},new?Organization?{?Id?=?HierarchyId.Parse("/2/"),?Name?=?"分公司2"?},?new?Organization?{?Id?=?HierarchyId.Parse("/1/1/"),?Name?=?"部門A"?},?new?Organization?{?Id?=?HierarchyId.Parse("/1/1/1/"),?Name?=?"小組X"?},?new?Organization?{?Id?=?HierarchyId.Parse("/1/1/2/"),?Name?=?"小組Y"?});db.SaveChanges(); }//刪除分公司2 using?(var?db?=?new?DemoContext()) {db.Organizations.Remove(db.Organizations.Where(p?=>?p.Id?==?HierarchyId.Parse("/2/")).First());db.SaveChanges(); }//修改小組名稱 using?(var?db?=?new?DemoContext()) {var?team?=?db.Organizations.Where(p?=>?p.Id?==?HierarchyId.Parse("/1/1/1/")).First();team.Name?=?"Team1";team?=?db.Organizations.Where(p?=>?p.Id?==?HierarchyId.Parse("/1/1/2/")).First();team.Name?=?"Team2";db.SaveChanges(); }//查詢分公司1下的所有小組 using?(var?db?=?new?DemoContext()) {var?organizations=??db.Organizations.Where(p?=>?p.Id.GetLevel()==3?&&?p.Id.GetAncestor(2)==?HierarchyId.Parse("/1/")).OrderBy(p=>p.Id).ToList();foreach?(var?organization?in?organizations){Console.WriteLine(@$"{organization.Id}?{organization.Name}");} }運行成功:
如果你覺得這篇文章對你有所啟發,請關注我的個人公眾號”My IO“,記住我!
總結
以上是生活随笔為你收集整理的使用EF Core操作层次结构数据的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 自建PicGo图床
 - 下一篇: 温故知新,.Net Core遇见WinF