首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实体框架HierarchyId解决方法

实体框架HierarchyId解决方法
EN

Stack Overflow用户
提问于 2013-01-17 00:42:38
回答 2查看 14.1K关注 0票数 14

EF 5.0

我正在开发一个原型来一起测试hierarchyid和entity框架。我有以下架构:

代码语言:javascript
复制
Create Table dbo.Employee
(
   EmployeeId int identity not null,
   Name nvarchar(100) not null,
   Node hierarchyid not null,
   NodePath as Node.ToString() persisted,
   Level AS Node.GetLevel() persisted,
   ManagerNode as Node.GetAncestor(1) persisted,
   ManagerNodePath as Node.GetAncestor(1).ToString() persisted
);

Alter Table dbo.Employee
    Add Constraint EmployeePK Primary Key NonClustered (EmployeeId);

Go

--Enforce Hierarchy
Alter Table dbo.Employee
    Add Constraint EmployeeManagerNodeNodeFK Foreign Key (ManagerNode) References Employee(Node);
Go

Create Unique Clustered Index EmployeeDepthFirstIndex on dbo.Employee(Node);

Go

Create NonClustered Index EmployeeBreathFirstIndex on dbo.Employee(Level, Node);

Go

据我所知,EF目前不支持hierarchyid数据类型,但有些人建议了一些变通方法,比如创建计算列(Node.ToString()),就像我在上面做的那样。

有没有办法设置EF,让它识别父/子关系,这样我就可以有效地拥有一个从属集合?例如:

代码语言:javascript
复制
Employee.Subordinates

我唯一能想到的就是使用FK创建一个ManagerId列,但是我实际上是将层次结构存储在两个地方。

谢谢你的帮助!

EN

回答 2

Stack Overflow用户

发布于 2013-03-31 20:52:25

EF6现在是开源的,因此很容易添加HierarcyID支持。我也添加了它。您可以从codeplex:http://entityframework.codeplex.com/SourceControl/network/forks/zgabi/efhierarchyidrc1 (有时分支名称会更改)或NuGet:https://www.nuget.org/packages/EntityFrameworkWithHierarchyId/ Currenty EF6 is in RC1状态下载修改后的源代码和编译/签名的‘ll,但我会将修改合并到EF6的每个后续版本中。

我有以下模型:

代码语言:javascript
复制
public class Employee
{
    public int EmployeeId { get; set; }
    [Required, MaxLength(100)]
    public string Name { get; set; }
    [Required]
    public HierarchyId Node { get; set; }

    public IQueryable<Employee> GetSubordinates(MyContext context)
    {
        return context.Employees.Where(o => Node == o.Node.GetAncestor(1));
    }
}

public class MyContextInitializer : CreateDatabaseIfNotExists<MyContext>
{
    protected override void Seed(MyContext context)
    {
        context.Database.ExecuteSqlCommand(
            "ALTER TABLE [dbo].[Employees] ADD [ManagerNode] AS ([Node].[GetAncestor]((1))) PERSISTED");
        context.Database.ExecuteSqlCommand(
            "ALTER TABLE [dbo].[Employees] ADD CONSTRAINT [UK_EmployeeNode] UNIQUE NONCLUSTERED (Node)");
        context.Database.ExecuteSqlCommand(
            "ALTER TABLE [dbo].[Employees]  WITH CHECK ADD CONSTRAINT [EmployeeManagerNodeNodeFK] " +
            "FOREIGN KEY([ManagerNode]) REFERENCES [dbo].[Employees] ([Node])");
        context.Employees.Add(new Employee { Name = "Root", Node = new HierarchyId("/") });
        context.Employees.Add(new Employee { Name = "Emp1", Node = new HierarchyId("/1/") });
        context.Employees.Add(new Employee { Name = "Emp2", Node = new HierarchyId("/2/") });
        context.Employees.Add(new Employee { Name = "Emp3", Node = new HierarchyId("/1/1/") });
        context.Employees.Add(new Employee { Name = "Emp4", Node = new HierarchyId("/1/1/1/") });
        context.Employees.Add(new Employee { Name = "Emp5", Node = new HierarchyId("/2/1/") });
        context.Employees.Add(new Employee { Name = "Emp6", Node = new HierarchyId("/1/2/") });
    }
}

public class MyContext : DbContext
{
    public DbSet<Employee> Employees { get; set; }
}

生成的数据库:

代码语言:javascript
复制
CREATE TABLE [dbo].[Employees](
    [EmployeeId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](100) NOT NULL,
    [Node] [hierarchyid] NOT NULL,
    [ManagerNode]  AS ([Node].[GetAncestor]((1))) PERSISTED,
 CONSTRAINT [PK_dbo.Employees] PRIMARY KEY CLUSTERED 
(
    [EmployeeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
 CONSTRAINT [UK_EmployeeNode] UNIQUE NONCLUSTERED 
(
    [Node] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE [dbo].[Employees]  WITH CHECK ADD  CONSTRAINT [EmployeeManagerNodeNodeFK] FOREIGN KEY([ManagerNode])
REFERENCES [dbo].[Employees] ([Node])

获取Emp1 employee子节点的示例:

代码语言:javascript
复制
    using (var c = new MyContext())
    {
        var firstItem = c.Employees.Single(o => o.Node == new HierarchyId("/1/"));

        foreach (var table1 in firstItem.GetSubordinates(c))
        {
            Console.WriteLine(table1.EmployeeId + " " + table1.Name);
        }
    }

结果:

代码语言:javascript
复制
4 Emp3
7 Emp6
票数 21
EN

Stack Overflow用户

发布于 2016-10-23 22:28:23

使用varbinary(892)而不是hierarchyid。EF识别返回字节数组的varbinary。您可以将字节数组转换为SqlHierarchyid类型,并使用hyrarchy pod函数。有了这个变通方法,您甚至可以在其他数据库中使用hierarchyid函数。有关更多详细信息和指向nugget和github的链接,请参阅http://www.casavillar.com.br/blog,您可以在其中找到包括MySql在内的示例

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14363332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档