【问题标题】:NHibernate QueryOver with Nested Classes带有嵌套类的 NHibernate QueryOver
【发布时间】:2015-04-24 04:11:35
【问题描述】:

我正在使用 NHibernate 的 QueryOver 来填充具有许多嵌套类的类的 IEnumerable。但是,这会在 Sql Profiler 中产生很多单独的选择语句。使用下面的示例,NHibernate 从 foo 表中选择结果,然后“循环”通过结果集中的每一行,从 bar、foobar 等中选择。理想情况下,我希望这是一个使用连接的选择语句,但我'不确定这是否可能。

我认为问题可能在于映射中的 Not.LazyLoad() 方法。

鉴于这些类和映射:

public class Foo
{
    public virtual int FooId {get; set;}
    public virtual Bar Bar {get; set;}
    public virtual Baz Baz {get; set;}
}

public class Bar
{
    public virtual int BarId {get; set;}
    public virtual FooBar FooBar {get; set;}
    ...
}

public class FooMap : ClassMap<Foo>{
    public FooMap(){
        Schema("my_schema");
        Table("foo");
        LazyLoad();
        Id(x => x.FooId).GeneratedBy.Identity().Column("foo_id");
        References(x => x.Bar).Column("bar").Not.LazyLoad();
        References(x => x.Baz).Column("baz").Not.LazyLoad();
    }
}

public class BarMap : ClassMap<Bar>{
    public BarMap(){
        Schema("my_schema");
        Table("bar");
        LazyLoad();
        Id(x => x.FooId).GeneratedBy.Identity().Column("bar_id");
        References(x => x.FooBar).Column("foo_bar").Not.LazyLoad();
    }
}

我正在通过以下方式使用 queryover 来填充 IEnumerable:

IEnumerable<Foo> foos;

using (ISession session = NHibernateSessionFactoryManager.Factory.OpenSession())
{
    foos = session.QueryOver<foos>()
        .Where(f => f.Baz.BazId == bazId).List();
}

这是我的 NHibernateSesssionFactory 管理器类:

public class NHibernateSessionFactoryManager {
    private static readonly Object lockObject = new object();
    private static readonly ISessionFactory SessionFactory = BuildSessionFactory();

    private static ISessionFactory BuildSessionFactory(){
        lock (lockObject){//make sure only one session factory is created per start of the app
            return Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                    .ConnectionString(c => c
                        .FromConnectionStringWithKey("foobardb")))
                .Mappings(m =>
                    m.FluentMappings.AddFromAssemblyOf<FooMap>())
                //.ExposeConfiguration(BuildSchema)
                .BuildSessionFactory();
        }
    }

    private static void BuildSchema(Configuration config) {
        // export the database schema
        new SchemaExport(config)
            .Create(true,false);
    }

    public static ISession OpenSession(){
        return Factory.OpenSession();
    }

    public static ISessionFactory Factory{
        get{
            return SessionFactory;
        }
    }
}

【问题讨论】:

    标签: c# nhibernate fluent-nhibernate


    【解决方案1】:

    这可以通过 Futures 来实现,请在下面找到您的示例的完整代码,

    public class FooBar
    {
        public virtual int FooBarId { get; set; }
        public virtual string FooBarName { get; set; }
    }
    
    public class FooBarMap : ClassMap<FooBar>
    {
        public FooBarMap()
        {
            Table("foorbar");
            LazyLoad();
            Id(x => x.FooBarId).GeneratedBy.Identity().Column("foobar_id");
            Map(x => x.FooBarName);
        }
    }
    
    public class Bar
    {
        public virtual int BarId {get; set;}
        public virtual FooBar FooBar {get; set;}
        public virtual string BarName { get; set; }
    }
    
    public class BarMap : ClassMap<Bar>
    {
        public BarMap()
        {
            Table("bar");
            LazyLoad();
            Id(x => x.BarId).GeneratedBy.Identity().Column("bar_id");
            Map(x => x.BarName);
            References(x => x.FooBar).Column("foo_bar").Not.LazyLoad();
        }
    }
    
    public class Baz
    {
        public virtual int BazId {get; set;}
        public virtual string BazName { get; set; }
    }
    
    public class BazMap : ClassMap<Baz>
    {
        public BazMap()
        {
            Table("baz");
            LazyLoad();
            Id(x => x.BazId).GeneratedBy.Identity().Column("baz_id");
            Map(x => x.BazName);
        }
    }
    
    public class Foo
    {
        public virtual int FooId { get; set; }
        public virtual Bar Bar { get; set; }
        public virtual Baz Baz { get; set; }
        public virtual string FooName { get; set; }
    }
    
    public class FooMap : ClassMap<Foo>
    {
        public FooMap()
        {
            Table("foo");
            LazyLoad();
            Id(x => x.FooId).GeneratedBy.Identity().Column("foo_id");
            Map(x => x.FooName);
            References(x => x.Bar).Column("bar").Not.LazyLoad();
            References(x => x.Baz).Column("baz").Not.LazyLoad();
        }
    }
    

    此测试使用未来查询,

    [Test]
    public void FutureTest()
    {
        using (ISession session = _sessionFactory.OpenSession())
        {
            var tx = session.BeginTransaction();
            for (int i = 0; i < 5; i++)
            {
                var fb = new FooBar() {FooBarName = "FooBar_" + i};
                session.Save(fb);
                var bz = new Baz() { BazName = "Baz_" + i};
                session.Save(bz);
                var b = new Bar() { BarName = "Bar_" + i ,FooBar = fb};
                session.Save(b);
                var f = new Foo() { FooName = "Foo_" + i , Bar = b,Baz = bz};
                session.Save(f);
            }
            session.Flush();
            tx.Commit();
        }
    
        using (ISession session = _sessionFactory.OpenSession())
        {
            Foo fooAlias = null;
            Bar barAlias = null;
            Baz bazAlias = null;
            FooBar fooBarAlias = null;
    
            var tx = session.BeginTransaction();
    
            var fooList = session.QueryOver<Foo>(() => fooAlias)
                .JoinAlias(f => f.Bar, () => barAlias)
                .JoinAlias(f => f.Baz, () => bazAlias)
                .JoinAlias(f => f.Bar.FooBar, () => fooBarAlias)
                .Future<Foo>().Distinct().ToList();
    
            foreach (var foo in fooList)
            {
                Console.WriteLine(foo.FooName);
                Console.WriteLine(foo.Bar.BarName);
                Console.WriteLine(foo.Baz.BazName);
                Console.WriteLine(foo.Bar.FooBar.FooBarName);
            }
            session.Flush();
            tx.Commit();
        }
    }
    

    产生的单个 SQL 是,

    SELECT this_.foo_id as foo1_5_3_, this_.FooName as FooName5_3_, this_.bar as bar5_3_, this_.baz as baz5_3_, baralias1_.bar_id as bar1_1_0_, baralias1_.BarName as BarName1_0_, baralias1_.foo_bar as foo3_1_0_, foobaralia3_.foobar_id as foobar1_4_1_, foobaralia3_.FooBarName as FooBarName4_1_, bazalias2_.baz_id as baz1_2_2_, bazalias2_.BazName as BazName2_2_ FROM foo this_ inner join bar baralias1_ on this_.bar=baralias1_.bar_id inner join foorbar foobaralia3_ on baralias1_.foo_bar=foobaralia3_.foobar_id inner join baz bazalias2_ on this_.baz=bazalias2_.baz_id;
    

    输出,

    Foo_0
    Bar_0
    Baz_0
    FooBar_0
    Foo_1
    Bar_1
    Baz_1
    FooBar_1
    Foo_2
    Bar_2
    Baz_2
    FooBar_2
    Foo_3
    Bar_3
    Baz_3
    FooBar_3
    Foo_4
    Bar_4
    Baz_4
    FooBar_4
    

    【讨论】:

      【解决方案2】:

      如果您通过Join 加载的内容,请使用QueryOver API 来完成工作:

      foos = session.QueryOver<Foo>()
          .JoinAlias(x => x.Bar, () => barAlias)
          .JoinAlias(x => x.Bar, () => barAlias)
          .JoinAlias(() => barAlias.FooBar, () => fooBarAlias)
          .List();
      

      如果您使用原始查询默认加载什么,请将映射更改为 Fetch.Join() 而不是 Not.LazyLoad()

      注意重复数据,你可以阅读它here。或者使用具有不同的投影。

      【讨论】:

      • 感谢您提供有关重复数据的信息。我会记住这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多