rbe*_*amy 11 nhibernate nhibernate-mapping
我正在尝试让NHibernate使用集合的许多方面来管理双向关联以建立零对一关系.
父类和地图:
public class Parent
{
private ICollection<Child> children;
public Parent()
{
this.children = new HashedSet<Child>();
}
public virtual Guid Id { get; protected internal set; }
public virtual Child Child
{
get { return children.FirstOrDefault(); }
set
{
{
this.children.Clear();
if (value != null)
{
this.children.Add(value);
}
}
}
}
}
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
this.Id(x => x.Id)
.GeneratedBy.GuidComb();
this.HasMany<Child>(Reveal.Member<Parent>("children"))
.Access.Field()
.Cascade.All()
.Not.Inverse()
.AsSet();
}
}
Run Code Online (Sandbox Code Playgroud)
儿童班和地图:
public class Child
{
public virtual Guid Id { get; protected internal set; }
public virtual Parent Parent { get; set; }
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
this.Id(x => x.Id)
.GeneratedBy.GuidComb();
this.References(x => x.Parent)
.Not.Nullable()
.Cascade.All();
}
}
Run Code Online (Sandbox Code Playgroud)
以下代码生成两个插入和更新:
var parent = new Parent();
var child = new Child();
parent.Child = child;
child.Parent = parent;
session.Save(parent);
session.Flush();
Run Code Online (Sandbox Code Playgroud)
注意第二个插入和以下更新的基本上重复的SQL:
exec sp_executesql N'INSERT INTO [Parent] (Id) VALUES (@p0)',N'@p0 uniqueidentifier',@p0='AA5A146E-E3F5-4373-B7A8-9EF301171401'
go
exec sp_executesql N'INSERT INTO [Child] (Parent_id, Id) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='AA5A146E-E3F5-4373-B7A8-9EF301171401',@p1='B78C4461-A217-47FC-BE02-9EF30117140A'
go
exec sp_executesql N'UPDATE [Child] SET Parent_id = @p0 WHERE Id = @p1',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='AA5A146E-E3F5-4373-B7A8-9EF301171401',@p1='B78C4461-A217-47FC-BE02-9EF30117140A'
go
Run Code Online (Sandbox Code Playgroud)
虽然这段代码产生臭名昭着not-null property references a null or transient value inverse
:
var parent = new Parent();
var child = new Child();
parent.Child = child;
//child.Parent = parent;
session.Save(parent);
session.Flush();
Run Code Online (Sandbox Code Playgroud)
我发现这个职位很多,但还没有找到如何做零到一的,有一个明确的指导inverse=false
上one
侧.
我尝试过这里提到的一对多/一对一的方法.
同样,我在NHibernate上发现了几个关于(不)可以为空的外键的公开问题:NH-941,NH-1050等.
我究竟做错了什么?
编辑2011-05-30
所以,我的临时解决方案是inverse=true
在多方面采用标准设置,并在父设置器中做一些魔术:
public virtual Child Child
{
get { return children.FirstOrDefault(); }
set
{
{
this.children.Clear();
if (value != null)
{
value.Parent = this;
this.children.Add(value);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
但我仍然由百思不得其解inverse=false
的行为,这应该是相当于inverse=true
上多到一侧(有趣的是,FluentNhibernate不允许的ManyToOnePart设置inverse=true
像这样的文章建议).
Dan*_*ing 32
该inverse
属性用于帮助NHibernate知道应该使用哪个关系来维持关系.非反面(请注意双重否定)是将持续存在的一面.如果任何一方都不是反向的,那么这种关系将持续两次,就像INSERT
后面UPDATE
你提供的一个例子一样.如果双方都是反向的,则关系将不会持续存在,因此正确设置反向非常重要.
我想以inverse
下面的方式思考.我不知道这是否正式是它的工作方式,但它有助于我的世界有意义:
many-to-one
关系总是如此inverse="false"
.它们始终用于保持与数据库的关系.由于它们总是inverse="false"
存在,因此无需指定它,因此NHibernate(以及Fluent NHibernate)不提供它的选项.
(我只遇到了一个我希望我可以指定inverse="true"
的情况many-to-one
.如果你有one-to-many
list
一方many-to-one
在另一方,你应该能够list
控制关系,以便NHibernate可以负责设置index
你现在的价值观,你必须在子类中添加一个属性并index
自己管理这些值.)
one-to-one
关系总是如此inverse="true"
.如果没有关系id
或many-to-one
关系的另一方,他们就永远不会存在,这将保持这种关系.由于inverse
值始终相同,因此无需指定它,因此不支持指定它.
像类别bag
,list
,set
等可以或可以不是双向关系的一部分.如果它们本身存在(也许是一包字符串元素),那么它们需要inverse="false"
(这是默认值),因为没有其他人负责持久化关系.但是,如果它们与另一种关系一起存在(如传统的一对多/多对一),则应将它们指定为inverse="true"
.
如果many-to-many
集合中您在关系的任一侧有一个集合,请将其中一个标记为inverse="true"
,并将另一个作为默认值inverse="false"
.同样,关键是关系的一方必须是非反向的.你应该选择哪一方?例如,如果我们在用户和角色之间采用多对多关系,那么您可能拥有大量用户和一些角色.在我看来,你应该映射Role.Users
为inverse="true"
并User.Roles
控制关系,因为它是一个较小的数据集,它可能是你更关心的集合.
(事实上,我会犹豫是否要包含Role.Users
在模型中.假设"客户"角色有100,000个用户.然后customerRole.Users
是一个无法使用的延迟加载炸弹等待爆炸.)
由于关系的哪一侧是反向的并不重要,只要一方是非反向的,那么你应该把one-to-one
方面作为反面,因为这是NHibernate想要的方式.不要在无关紧要的事情上对抗工具.在您提供的映射中,关系的两侧基本上都标记为非反向,这导致关系持续两次.以下映射应该更适合您:
public class Parent
{
public virtual Guid Id { get; set; }
public virtual Child Child { get; set; }
}
public class ParentClassMap : ClassMap<Parent>
{
public ParentClassMap()
{
Id(x => x.Id);
HasOne(x => x.Child)
.PropertyRef(x => x.Parent)
.Cascade.All();
}
}
public class Child
{
public virtual Guid Id { get; set; }
public virtual Parent Parent { get; set; }
}
public class ChildClassMap : ClassMap<Child>
{
public ChildClassMap()
{
Id(x => x.Id);
References(x => x.Parent)
.Not.Nullable()
.Unique()
.Cascade.SaveUpdate();
}
}
Run Code Online (Sandbox Code Playgroud)
...导致测试插入代码中出现以下SQL:
exec sp_executesql N'INSERT INTO [Parent] (Id) VALUES (@p0)',N'@p0 uniqueidentifier',@p0='925237BE-558B-4985-BDA2-9F36000797F5'
exec sp_executesql N'INSERT INTO [Child] (Parent_id, Id) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='925237BE-558B-4985-BDA2-9F36000797F5',@p1='BE6D931A-8A05-4662-B5CD-9F36000797FF'
Run Code Online (Sandbox Code Playgroud)
没有更新查询!
归档时间: |
|
查看次数: |
3263 次 |
最近记录: |