我们遇到一种情况,即在NHibernate会话上启动事务,将一些行填充到几个表中,并执行一个查询,在两个表上执行连接。
型号:
char*
NHibernate地图:
public class A
{
public virtual string ID { get; set; } // Primary key
public IList<B> Bs { get; set; }
}
public class B
{
public virtual string ID { get; set; } // Foreign key
}
启动事务并执行以下代码:
public class AMap: ClassMap<A>
{
public AMap()
{
Table("dbo.A");
Id(x => x.ID).Not.Nullable();
HasMany(u => u.Bs).KeyColumn("ID");
}
}
public class BMap: ClassMap<B>
{
public BMap()
{
Table("dbo.B");
Map(x => x.ID, "ID").Not.Nullable();
}
}
结果是A的列表。在列表中,A的对象没有填充B。
虽然此示例已简化,但相关实际对象具有与相应表列关联的其他属性;所有这些属性按预期填充;该问题仅限于映射为HasMany(外键关联)的属性。
如果首先填充表,然后执行查询(作为单独的进程或在连续的事务中),A的对象确实正确填充了它们的B。换句话说,似乎在事务中执行的查询无法看到先前在同一事务中执行的插入的完整效果。
检查NHibernate生成的SQL确认它正确执行了所有插入并正确地表达了连接查询;它似乎没有正确填充查询结果中的对象。
是否需要执行特殊步骤以确保通过NHibernate执行的数据库插入/更新对同一事务中的后续提取完全可见?
答案 0 :(得分:0)
HasMany(u => u.Bs).KeyColumn("ID");
对我来说不对。一对多关系的id应为A_ID
。
你在代码中做了很多奇怪的事情。我希望你的真实代码看起来不像这样。您不应该直接设置外键。他们由NH管理。你不应该一直冲洗。通常你永远不会冲洗。
另请注意,左外连接不用于填充A中的B列表。(NHibernate没有关于这将是一个有效选项的信息。)有加载实体的映射技巧及其中一个集合在一个查询中,但这大部分时间都不是一个好主意,我建议不要尝试这个,除非你真的了解NH以及如何处理查询得很好。如果不完全破坏它,您将只获得相同的A多次和一些性能问题。如果你害怕N + 1问题(我希望你是),请改用批量大小。
答案 1 :(得分:0)
找出解决方案。它的要点是添加&#34;孩子&#34;物品到&#34;父母&#34;然后保存。
所以...班级现在看起来像:
public class A
{
public virtual string ID { get; set; } // Primary key
public virtual IList<B> Bs { get; set; }
}
public class B
{
public virtual A A { get; set; } // Foreign key now expressed as reference to "parent" object instead of property containing key value
}
父级和子级的ClassMaps将关系表示为对象/列表:
public class AMap: ClassMap<A>
{
public AMap()
{
Table("dbo.A");
Id(x => x.ID).Not.Nullable();
HasMany(u => u.Bs).KeyColumn("ID").Cascade.SaveUpdate();
}
}
public class BMap: ClassMap<B>
{
public BMap()
{
Table("dbo.B");
Map(x => x.ID, "ID").Not.Nullable();
References(x => x.A, "ID").Not.Nullable();
}
}
最后,通过在保存对象及其关系之前构建对象来保存数据,即与对象一起保存关系:
var a1 = new A
{
ID = "One"
};
var b1 = new B
{
A = a1
};
a1.Bs = new []{b1};
session.Save(a1);
var a2 = new A
{
ID = "Two"
};
var b2 = new B
{
A = a2
};
a2.Bs = new []{b2};
session.Save(a2);
session.Flush();
此查询:
A a = null;
B b = null;
var result = _session.QueryOver(() => a)
.JoinQueryOver(() => a.Bs, () => b,JoinType.LeftOuterJoin)
.List();
现在返回预期结果,并在同一会话/事务中。