目前微软的ORM家族都无法使用CLR用户定义类型(包括内置的和地理空间类型)作为列类型。
如果您在数据库中使用这些类型,有两种解决方法:
在层次结构表中添加一个计算列,表达式为CAST(hid AS varbinary892))
。你需要确保在每个查询(包括存储过程)中都包含这个列,以便Linq使用。然后,将此列添加到实体映射中。
此时,您可以扩展实体的部分类,通过添加对Microsoft.SqlServerTypes
的引用并使用BinaryReader
/BinaryWriter
类将BLOB数据转换为/from SqlHierarchyId
,添加“真正的”hierarchyid
列作为其自己的属性。
请注意,您不能针对此列编写Linq查询。如果尝试,您将只会得到“不支持的翻译”错误。因此,请记住,这是一个有限的解决方法。
另一个选择,也是我通常喜欢的选择,是完全不使用L2S/EF中的hierarchyid
列。在层次结构表中添加一个单独索引的代理自动增量键,并将hierarchyid
视为实现细节。使用UDF和视图来实现仅需要代理ID作为参数的分层查询。
这听起来很麻烦,但如果从一开始就这样工作,实际上并不那么糟糕。在Microsoft引入hierarchyid
类型之前,我正在使用Dennis Forbes的材料化路径层次结构的适应版本,它基于相邻列表并维护路径作为某种反规范化。 hierarchyid
使这个过程变得更加容易。
不幸的是,我没有一个完整的工作示例来维护hierarchyid
和相邻列表之间的正确关联,但是如果您阅读Dennis的文章,它应该是一个良好的开端。不要实现材料化路径,改用hierarchyid
,但是请阅读有关使用触发器实现自我维护层次结构的部分。
如果Microsoft在他们的ORM中实现对hierarchyid
的支持,那么删除相邻列表并完全切换到基于hierarchyid
的解决方案将变得容易。但是由于管理基于hierarchyid
的层次结构需要大量存储过程来进行维护(因为您不会得到“自动”ID),因此您应该熟悉编写大量SQL UDF和存储过程抽象层次查询。
我们使用与Aaronaught类似的Linq to SQL解决方案。
我们创建了计算列。
TreeId.ToString()
针对当前的层次结构ID列和
[TreeId].[GetAncestor](1).ToString()
针对直接父级。
我们还创建了一个视图,排除了层次结构ID列,并将此视图拖到Dbml图上,并设置与引用表的关联。
大多数层次结构ID功能都需要以存储过程的形式存在。