代码之家  ›  专栏  ›  技术社区  ›  Nick Swarr

NHibernate和继承是否会创建意外的双查询行为?

  •  4
  • Nick Swarr  · 技术社区  · 15 年前

    我在用FluentHibernate。我没有使用自动映射。我有一个子类的基类。当我对基类进行查询时,它会对子类执行额外的查询。以下是我所做的(人为的)例子:

    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();
    }
    
    2 回复  |  直到 15 年前
        1
  •  4
  •   Diego Mijelshon    15 年前

    你看到的是预期的行为。

    查询基类也会查询任何继承的类。

    如果有一个显式的nhibernate映射(子类、联合子类等),那么这只是一个查询。否则,它被视为隐式多态定义,并发出两个查询来返回所有查询的结果。

    我相信(从文档中,我没有尝试过)通过将类映射为 polymorphism="explicit" . 我不知道Fluent是否支持它。

        2
  •  0
  •   Jamie Ide    15 年前

    尝试:

    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");
        }
    }
    

    您仍然有问题,因为foo和fooudit的标识符不同。如果fooudit是foo的子类,那么它应该具有存储在foo表中的相同标识符。

    基于op comment的更新:您当然可以在域模型中有一个继承链,而不需要在nhibnerate中表达它。只需将fooauditmap更改为inherit ClassMap<FooAudit> . 但是,对foo类型的对象的查询将不包括任何fooaudit类型,因为nh不知道这种关系。

    但我认为你们之间的关系是一对多的——foo有一组fooaudits——你们应该用这种方式来映射它。

    更新2:我之前的语句“但是您对foo类型的对象的查询将不包括任何fooaudit类型,因为nh不知道这种关系。”似乎是错误的。有一种方法可以通过使用 special class property 但这不是一个很好的解决办法。

    我认为您最好摆脱继承,让两个类都实现一个接口或将公共属性映射为组件。