Entity framework 实体框架层次结构解决方案

Entity framework 实体框架层次结构解决方案,entity-framework,entity-framework-5,Entity Framework,Entity Framework 5,EF 5.0 我正在开发一个原型来共同测试hierarchyid和实体框架。我有以下模式: 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() persist

EF 5.0

我正在开发一个原型来共同测试hierarchyid和实体框架。我有以下模式:

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,使其能够识别父/子关系,从而有效地拥有下属集合?e、 g

Employee.Subordinates
我唯一能想到的是创建一个带有FK的ManagerId列,但是我实际上是在两个地方存储层次结构


谢谢你的帮助

EF6现在是开源的,所以添加层次结构支持很容易。我也加了。 您可以从codeplex下载已修改的源代码和已编译/已签名的DLL: (有时fork名称会更改) 或者来自NuGet: 当前EF6处于RC1状态,但我会将修改合并到EF6的每个后续版本中

我有以下型号:

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; }
}
获取Emp1 employee子节点的示例:

    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);
        }
    }
结果:

4 Emp3
7 Emp6
使用varbinary(892)代替hierarchyid。 EF识别varbinary返回字节数组。 您可以将字节数组转换为SqlHierarchyid类型,并使用hyrarchy pod函数。 通过这种解决方法,您甚至可以在其他数据库中使用hierarchyid函数。
请参阅更多详细信息和指向nugget和github的链接,在那里您可以找到包括MySql在内的示例

@zgabi好奇为什么这没有成为正式版本???@BZ-实体框架团队认为层次结构支持的需求不足以实现它,显然,他们最近如何实现其他类似类型的应用程序存在一些复杂问题,他们希望避免这些问题,而是使用某种扩展框架来处理这些问题。但他们没有时间进行6 RTM。可能在将来的更新中:(不幸的是,其他二进制文件依赖于具有特定公钥的EF(ASP.NET标识),这意味着不可能始终使用此库。@zgavi,repo的问题在于它是一个fork,而不是一个扩展。它已合并到官方EF中,因此公钥问题将在以下版本中解决。
4 Emp3
7 Emp6