如何避免NHibernate N+;1具有复合键

如何避免NHibernate N+;1具有复合键,nhibernate,queryover,select-n-plus-1,Nhibernate,Queryover,Select N Plus 1,编辑我为这个问题重新制作了整个项目。因此,我重新提出了这个问题 我希望能够有效地避免N+1和笛卡尔连接,将4层深度的实体与第三层上的复合关键点连接在一起 我希望这只在几个查询中完成,而不是延迟加载,也不是将所有表连接在一起 A-(多)->B-(多)->C-(复合,单)->D 比如: Select * From A Left Join B On A.Id = B.AId Select * From B Left Join C On B.Id = C.BId Inner Join D On C.DI

编辑我为这个问题重新制作了整个项目。因此,我重新提出了这个问题

我希望能够有效地避免N+1和笛卡尔连接,将4层深度的实体与第三层上的复合关键点连接在一起

我希望这只在几个查询中完成,而不是延迟加载,也不是将所有表连接在一起

A-(多)->B-(多)->C-(复合,单)->D

比如:

Select * From A Left Join B On A.Id = B.AId
Select * From B Left Join C On B.Id = C.BId Inner Join D On C.DId = D.Id
下面是使用的代码 这是一个功能齐全的应用程序。 我使用NuGet安装Sqlite x86、StructureMap、NHProf和Fluent NH

StructureMapServiceLocator:

namespace MyTest.NHibernateTest
{
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.ServiceLocation;
using StructureMap;

public class StructureMapServiceLocator : ServiceLocatorImplBase
{
    private readonly IContainer _container;

    public StructureMapServiceLocator(IContainer container)
    {
        _container = container;
    }

    public IContainer Container { get { return _container; } }

    protected override object DoGetInstance(Type serviceType, string key)
    {
        return string.IsNullOrEmpty(key)
                   ? _container.GetInstance(serviceType)
                   : _container.GetInstance(serviceType, key);
    }

    protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
    {
        return _container.GetAllInstances(serviceType).Cast<object>().AsEnumerable();
    }

    public override TService GetInstance<TService>()
    {
        return _container.GetInstance<TService>();
    }

    public override TService GetInstance<TService>(string key)
    {
        return _container.GetInstance<TService>(key);
    }

    public override IEnumerable<TService> GetAllInstances<TService>()
    {
        return _container.GetAllInstances<TService>();
    }
}
}
名称空间MyTest.NHibernateTest
{
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用Microsoft.Practices.ServiceLocation;
使用结构图;
公共类StructureMapServiceLocator:ServiceLocatorImplBase
{
专用只读IContainer\u容器;
公共结构MapServiceLocator(IContainer容器)
{
_容器=容器;
}
公共IContainer容器{get{return\u Container;}}
受保护的重写对象DoGetInstance(类型serviceType,字符串键)
{
返回字符串.IsNullOrEmpty(键)
?_container.GetInstance(serviceType)
:_container.GetInstance(serviceType,key);
}
受保护的重写IEnumerable DoGetAlliances(类型serviceType)
{
return _container.GetAllInstances(serviceType.Cast().AsEnumerable();
}
公共覆盖TService GetInstance()
{
返回_container.GetInstance();
}
公共覆盖TService GetInstance(字符串键)
{
return\u container.GetInstance(key);
}
公共重写IEnumerable GetAllInstances()
{
return_container.GetAllInstances();
}
}
}
评价学

namespace MyTest.NHibernateTest
{
using System;
using System.Collections.Generic;
using System.Linq;
using StructureMap.Configuration.DSL;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Cfg;
using NHibernate;
using NHibernate.Tool.hbm2ddl;
using FluentNHibernate.Automapping;
using FluentNHibernate.Data;

public class AppRegistry : Registry
{
    public AppRegistry()
    {
        var dbConfiguration = SQLiteConfiguration.Standard
            .ConnectionString("Data Source=sqlite.db;Version=3;New=True;");
        dbConfiguration.ShowSql();

        var cfg = Fluently.Configure()
            .Database(dbConfiguration)
            .Mappings(m =>
            {
                m.AutoMappings.Add(AutoMap.AssemblyOf<Program>().Where(t =>
                {
                    return typeof(Entity).IsAssignableFrom(t);
                }));
            })
            .ExposeConfiguration(c =>
            {
                if (RebuildSchema.Value)
                    new SchemaExport(c).Create(false, true);
            });
        var sessionFactory = cfg.BuildSessionFactory();

        For<ISessionFactory>().Singleton().Use(sessionFactory);
        For<ISession>().HybridHttpOrThreadLocalScoped().Use(cx =>
        {
            var session = cx.GetInstance<ISessionFactory>().OpenSession();
            session.FlushMode = FlushMode.Commit;

            return session;
        });
    }
}
}
名称空间MyTest.NHibernateTest
{
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用StructureMap.Configuration.DSL;
使用FluentNHibernate.Cfg.Db;
使用FluentNHibernate.Cfg;
使用NHibernate;
使用NHibernate.Tool.hbm2ddl;
使用FluentNHibernate.自动映射;
使用FluentNHibernate.Data;
公共类权限:注册表
{
公共评估学()
{
var dbConfiguration=SQLiteConfiguration.Standard
.ConnectionString(“数据源=sqlite.db;版本=3;新建=True;”;
dbConfiguration.ShowSql();
var cfg=fluntly.Configure()
.数据库(数据库配置)
.Mappings(m=>
{
m、 添加(AutoMap.AssemblyOf()。其中(t=>
{
返回类型(实体)。IsAssignableFrom(t);
}));
})
.ExposeConfiguration(c=>
{
if(重建模式值)
新建SchemaExport(c).Create(false,true);
});
var sessionFactory=cfg.BuildSessionFactory();
For().Singleton().Use(sessionFactory);
For().HybridHttpOrthReadLocalScope().Use(cx=>
{
var session=cx.GetInstance().OpenSession();
session.FlushMode=FlushMode.Commit;
返回会议;
});
}
}
}
上市实体:

namespace MyTest.NHibernateTest.Entities
{
using System;
using System.Collections.Generic;
using System.Linq;
using FluentNHibernate.Data;

public class Listing : Entity
{
    public Listing()
    {
        Items = new List<ListingItem>();
    }
    public virtual IList<ListingItem> Items { get; set; }
}

public class ListingItem : Entity
{
    public ListingItem()
    {
        Values = new List<ListingItemValue>();
    }
    public virtual IList<ListingItemValue> Values { get; set; }
}

public class ListingItemValue : Entity
{
    public virtual ListingItem ListingItem { get; set; }
    public virtual ListingItemField ListingItemField { get; set; }
}

public class ListingItemField : Entity
{
    public virtual string Value { get; set; }
}
}
名称空间MyTest.NHibernateTest.Entities
{
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用FluentNHibernate.Data;
公共类列表:实体
{
公开上市()
{
项目=新列表();
}
公共虚拟IList项{get;set;}
}
公共类ListingItem:实体
{
公共列表项()
{
值=新列表();
}
公共虚拟IList值{get;set;}
}
公共类ListingItemValue:实体
{
公共虚拟ListingItem ListingItem{get;set;}
公共虚拟ListingItemField ListingItemField{get;set;}
}
公共类ListingItemField:实体
{
公共虚拟字符串值{get;set;}
}
}
程序(控制台):

名称空间MyTest.NHibernateTest
{
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用结构图;
使用hibertingrhinos.Profiler.Appender.NHibernate;
使用Microsoft.Practices.ServiceLocation;
使用NHibernate;
使用系统线程;
使用NHibernate.Transform;
使用MyTest.NHibernateTest.Entities;
公共静态类重建模式
{
公共静态布尔值{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
RebuildSchema.Value=true;
设置();
BuildData();
工作();
Console.ReadLine();
}
静态无效设置()
{
NHibernateProfiler.Initialize();
ObjectFactory.Initialize(x=>
{
x、 扫描(s=>
{
s、 装配件();
s、 查找注册表();
});
});
ServiceLocator.SetLocatorProvider(()=>new StructureMapServiceLocator(ObjectFactory.Container));
}
静态void BuildData()
{
var s=ObjectFactory.GetInstance();
使用(var t=s.BeginTransaction())
{
var listing=新列表();
s、 保存(列表);
var item=new ListingItem();
listing.Items.Add(item);
s、 保存(项目);
var item2=新列表项();
listing.Items.Add(item2);
s、 保存(项目2);
var field=new ListingItemField();
field.Value=“A”;
s、 保存(字段);
var field2=新的ListingItemField();
field2.Value=“B”;
s、 保存(字段2);
var值=新的ListingItemValue();
value.ListingItem=项目;
value.ListingItemField=字段;
项目.价值.增加(价值);
s、 保存(价值);
var value2=新的ListingItemValue();
value2.ListingItem=项目;
value2.ListingItemField=field2;
项目.价值.增加(价值2);
s、 保存(价值2);
namespace MyTest.NHibernateTest
{
using System;
using System.Collections.Generic;
using System.Linq;
using StructureMap;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using Microsoft.Practices.ServiceLocation;
using NHibernate;
using System.Threading;
using NHibernate.Transform;
using MyTest.NHibernateTest.Entities;

public static class RebuildSchema
{
    public static bool Value { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        RebuildSchema.Value = true;
        Setup();
        BuildData();
        Work();
        Console.ReadLine();
    }

    static void Setup()
    {
        NHibernateProfiler.Initialize();

        ObjectFactory.Initialize(x =>
        {
            x.Scan(s =>
            {
                s.TheCallingAssembly();
                s.LookForRegistries();
            });
        });

        ServiceLocator.SetLocatorProvider(() => new StructureMapServiceLocator(ObjectFactory.Container));
    }

    static void BuildData()
    {
        var s = ObjectFactory.GetInstance<NHibernate.ISession>();
        using (var t = s.BeginTransaction())
        {
            var listing = new Listing();
            s.Save(listing);

            var item = new ListingItem();
            listing.Items.Add(item);
            s.Save(item);

            var item2 = new ListingItem();
            listing.Items.Add(item2);
            s.Save(item2);

            var field = new ListingItemField();
            field.Value = "A";
            s.Save(field);

            var field2 = new ListingItemField();
            field2.Value = "B";
            s.Save(field2);

            var value = new ListingItemValue();
            value.ListingItem = item;
            value.ListingItemField = field;
            item.Values.Add(value);
            s.Save(value);

            var value2 = new ListingItemValue();
            value2.ListingItem = item;
            value2.ListingItemField = field2;
            item.Values.Add(value2);
            s.Save(value2);

            var value3 = new ListingItemValue();
            value3.ListingItem = item2;
            value3.ListingItemField = field;
            item2.Values.Add(value3);
            s.Save(value3);

            t.Commit();
        }
    }

    static void Work()
    {
        var s = ObjectFactory.GetInstance<ISession>();
        IList<Listing> foo;
        using (var t = s.BeginTransaction())
        {
            foo = s.QueryOver<Listing>()
                .Left.JoinQueryOver<ListingItem>(x => x.Items)
                .Left.JoinQueryOver<ListingItemValue>(x => x.Values)
                .Left.JoinQueryOver<ListingItemField>(x => x.ListingItemField)
                .TransformUsing(Transformers.DistinctRootEntity)
                .List();
            t.Commit();
        }

        try
        {
            Thread.Sleep(100);
            var x1 = foo[0];
            Thread.Sleep(100);
            var x2 = x1.Items[0];
            Thread.Sleep(100);
            var x3 = x2.Values[0];
            Thread.Sleep(100);
            var x4 = x2.Values[0].ListingItemField.Value;
        }
        catch (Exception) { }
    }
}
}
using (var t = s.BeginTransaction())
{
    ListingItem liAlias = null
    ListingItemValue livAlias = null;

    // 'Preload' all ListingItems with their Values and Fields
    s.QueryOver<ListingItem>()
        .JoinAlias(li => li.Values, () => livAlias, JoinType.LeftOuterJoin)
        .Fetch(_ => livAlias.ListingItemField).Eager
        .WithSubquery.WhereProperty(li => li.Id).In(
            QueryOver.Of<Listing>()
                .Where(l => l.Id == id)
                .JoinAlias(l => l.Items, () => liAlias, JoinType.LeftOuterJoin)
                .Select(_ => liAlias.Id)
        )
        .Future();

    // Get a single Listing w/ all its Items
    var listing = s.QueryOver<Listing>()
        .Fetch(l => l.Items).Eager
        .Where(l => l.Id == id)
        .FutureValue()
        .Value;

    t.Commit();
}