开发者

NHibernate and inheritance creating unexpected double query behavior?

开发者 https://www.devze.com 2023-01-05 02:11 出处:网络
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 (con

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号