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();
}
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.
Try:
public class FooAuditMap : SubclassMap<FooAudit>
{
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");
}
}
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.
精彩评论