我无法使用Fluent NHibernate映射树结构,而不必放入我认为是黑客的。
考虑以下课程:
Node
(摘要,有int Id
和GroupNode Parent
(如果null
,则节点位于根节点中))GroupNode
(继承自Node
,有IList<GroupNode> Groups
和IList<ItemNode> Items
)ItemNode
(继承自Item
)理想情况下,这将具有以下数据库结构:
我的地图制作者看起来像这样:
public class GroupNodeMap : ClassMap<GroupNode>
{
public GroupNode()
{
Id(x => x.Id);
References(x => x.Parent);
HasMany(x => x.Groups).LazyLoad();
HasMany(x => x.Items).LazyLoad();
}
}
public class ItemNodeMap : ClassMap<ItemNode>
{
public ItemNodeMap()
{
Id(x => x.Id);
References(x => x.Parent);
}
}
不幸的是,这会创建一组重复的引用(每个表都有ParentId
和GroupNodeId
。我可以通过在.KeyColumn("ParentId")
之后添加.LazyLoad()
来调整此行为,但这感觉就像一个黑客,我希望它使用约定或lambda而不是魔术字符串来表达。
有人能指出我正确的方向吗?
答案 0 :(得分:1)
以下是您可以尝试使用AutoMap约定和SQLite的示例:
namespace Entities
{
public abstract class Node
{
public virtual int Id { get; set; }
public virtual GroupNode Parent { get; set; }
}
public class ItemNode : Node
{
}
public class GroupNode : Node
{
public virtual IList<GroupNode> Groups { get; set; }
public virtual IList<ItemNode> Items { get; set; }
}
}
class Program
{
static void Main()
{
if (File.Exists("data.db3"))
{
File.Delete("data.db3");
}
using (var factory = CreateSessionFactory())
{
using (var connection = factory.OpenSession().Connection)
{
ExecuteQuery("create table GroupNode(Id integer primary key, Parent_Id integer)", connection);
ExecuteQuery("create table ItemNode(Id integer primary key, Parent_Id integer)", connection);
ExecuteQuery("insert into GroupNode(Id, Parent_Id) values (1, null)", connection);
ExecuteQuery("insert into GroupNode(Id, Parent_Id) values (2, 1)", connection);
ExecuteQuery("insert into GroupNode(Id, Parent_Id) values (3, 1)", connection);
ExecuteQuery("insert into ItemNode(Id, Parent_Id) values (1, 1)", connection);
ExecuteQuery("insert into ItemNode(Id, Parent_Id) values (2, 1)", connection);
}
using (var session = factory.OpenSession())
using (var tx = session.BeginTransaction())
{
var node = session.Get<GroupNode>(1);
tx.Commit();
}
}
}
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(
SQLiteConfiguration.Standard.UsingFile("data.db3").ShowSql()
)
.Mappings(
m => m.AutoMappings.Add(
AutoMap
.AssemblyOf<Program>()
.Where(t => t.Namespace == "Entities")
)
).BuildSessionFactory();
}
static void ExecuteQuery(string sql, IDbConnection connection)
{
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
command.ExecuteNonQuery();
}
}
}
答案 1 :(得分:0)
我的数据库中有完全相同类型的结构,我也使用了KeyColumn方法。它不是真正的黑客只是解释了fluentnhibernate这个系列另一面的名称是什么。
这是一个特例,因为通常如果设置“HasMany(x =&gt; x.Groups)”,他将在表Group中搜索“GroupId”。但在你的情况下,GroupId已经是该列的关键,它不是你想要用于此列的列。这就是为什么你必须设置“KeyColumn”来告诉fnh他应该使用哪一列作为关系。
经常使用KeyColumn方法,特别是在处理尚未为NHibernate构建的数据库时,并且列具有奇怪的名称。
答案 2 :(得分:-1)
Fluent NHibernate具有命名约定。 如果您不喜欢使用数据库列名(它不是黑客),则应重命名数据库列。 查看Available Conventions