NHibernate 和继承会造成意外的双重查询行为吗?
我正在使用 FluentNHibernate。我没有使用自动映射。我有一个子类化的基类。当我查询基类时,它会对子类执行额外的查询。这是我正在做的(人为的)示例:
public class Foo
{
int Id;
string SomeValue;
}
我创建另一个类来表示第一个类的审计记录,然后继承它:
public class FooAudit : Foo
{
DateTime DateModified;
}
我为每个进入其自己表的单独映射创建单独的映射:
public class FooMap : ClassMap<Foo>
{
public FooAuditMap()
{
Table("Foo");
Id(x => x.Id).Column("FOO_ID");
Map(x => x.SomeValue).Column("SOME_VALUE");
}
}
public class FooAuditMap : ClassMap<FooAuditMap>
{
public FooAuditMap()
{
Table("FooAudit");
CompositeId()
.KeyProperty(x => x.DateModified, c => c.ColumnName("AUDIT_DATE"));
.KeyProperty(x => x.Id, c => c.ColumnName("FOO_ID"));
Map(x => x.SomeValue).Column("SOME_VALUE");
}
}
我对 Foo 执行查询:
public virtual IEnumerable<Foo> List()
{
using (var session = SessionFactory.OpenSession())
{
return session.CreateCriteria<Foo>().List<Foo>();
}
}
然后它会两次访问数据库,一次是针对 Foo 执行查询,另一次是针对 FooAudit。
为什么它会发出两个查询?我生成了 HBM 文件,并且绝对没有任何东西链接这些类。
编辑:为了完整起见,这就是引导程序配置的样子。
public static ISessionFactory CreateSessionFactory()
{
return Fluently
.Configure()
.Database
(
FluentNHibernate.Cfg
.Db.MsSqlConfiguration.MsSql2005
.ConnectionString(GetConnectionString())
)
.Mappings(m => m
.FluentMappings.AddFromAssemblyOf<Foo>()
.Conventions.Add(typeof(EnumConvention)))
.BuildSessionFactory();
}
I'm using FluentNHibernate. I am not using auto-mapping. I have a base class that is subclassed. When I query against the base class then it performs an extra query against the subclass. Here's the (contrived) example of what I'm doing:
public class Foo
{
int Id;
string SomeValue;
}
I create another class that represents an audit record of the first and I inherit it:
public class FooAudit : Foo
{
DateTime DateModified;
}
I create separate mappings for each that go to their own tables:
public class FooMap : ClassMap<Foo>
{
public FooAuditMap()
{
Table("Foo");
Id(x => x.Id).Column("FOO_ID");
Map(x => x.SomeValue).Column("SOME_VALUE");
}
}
public class FooAuditMap : ClassMap<FooAuditMap>
{
public FooAuditMap()
{
Table("FooAudit");
CompositeId()
.KeyProperty(x => x.DateModified, c => c.ColumnName("AUDIT_DATE"));
.KeyProperty(x => x.Id, c => c.ColumnName("FOO_ID"));
Map(x => x.SomeValue).Column("SOME_VALUE");
}
}
I perform a query against Foo:
public virtual IEnumerable<Foo> List()
{
using (var session = SessionFactory.OpenSession())
{
return session.CreateCriteria<Foo>().List<Foo>();
}
}
Which then hits the DB twice, once to execute that query against Foo and again to FooAudit.
Why is it making two queries? I generated the HBM files and there is absolutely nothing linking these classes.
EDIT: For completeness, this is what the bootstrap config looks like.
public static ISessionFactory CreateSessionFactory()
{
return Fluently
.Configure()
.Database
(
FluentNHibernate.Cfg
.Db.MsSqlConfiguration.MsSql2005
.ConnectionString(GetConnectionString())
)
.Mappings(m => m
.FluentMappings.AddFromAssemblyOf<Foo>()
.Conventions.Add(typeof(EnumConvention)))
.BuildSessionFactory();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您所看到的是预期的行为。
查询基类也会查询任何继承的类。
如果有一个显式的 NHibernate 映射(子类、连接子类等),那么这将只是一个查询。否则,它被视为隐式多态定义,并且发出两个查询以返回所有查询的结果。
我相信(来自文档;我没有尝试过)您可以通过使用
polymorphism="explicit"
映射类来避免这种情况。不知道Fluent是否支持。What you are seeing is the expected behavior.
Querying a base class also queries any inherited classes.
If there is an explicit NHibernate mapping for that (subclass, joined-subclass, etc) that'll be just one query. Otherwise, it's considered an implicitly polymorphic definition, and two queries are issued to return results from all of them.
I believe (from the docs; I haven't tried) that you can avoid that by mapping the class with
polymorphism="explicit"
. I don't know if Fluent supports it.尝试:
您仍然遇到问题,因为 Foo 和 FooAudit 的标识符不同。如果 FooAudit 是 Foo 的子类,它应该在 Foo 表中存储相同的标识符。
根据OP评论进行更新:您当然可以在域模型中拥有继承链,而无需在NHibnerate中表达它。只需将 FooAuditMap 更改为继承
ClassMap
即可。但是,您对 Foo 类型的对象的查询将不包含任何 FooAudit 类型,因为 NH 不知道这种关系。但我认为这里是一对多的关系——Foo 有 FooAudit 的集合——你应该这样映射它。
更新 2:看来我之前的声明“但是您对 Foo 类型的对象的查询将不包含任何 FooAudit 类型,因为 NH 不知道这种关系。”是错误的。有一种方法可以通过使用 特殊类属性但这不是一个很好的解决方案。
我认为你最好摆脱继承,要么让两个类都实现一个接口,要么将公共属性映射为组件。
Try:
You still have a problem because the identifier for Foo and FooAudit are different. If FooAudit is a subclass of Foo it should have the same identifier stored in the Foo table.
Update based on OP comment: You can certainly have an inheritance chain in the domain model without expressing it in NHibnerate. Just change the FooAuditMap to inherit
ClassMap<FooAudit>
. However your query for object of type Foo will not include any FooAudit types because NH doesn't know about the relationship.But I think what you have here is a one-to-many relationship -- Foo has a collection of FooAudits -- and you should map it that way.
Update 2: It appears that my previous statement "However your query for object of type Foo will not include any FooAudit types because NH doesn't know about the relationship." is wrong. There is a way to return just the base class by restricting the results using the special class property but that's not a great solution.
I think you would be better off to get rid of the inheritance and either have both classes implement an interface or map the common properties as a component.