Nhibernate 通过左外连接进行大型一对多选择查询优化

Nhibernate 通过左外连接进行大型一对多选择查询优化,nhibernate,fluent-nhibernate,fluent-nhibernate-mapping,Nhibernate,Fluent Nhibernate,Fluent Nhibernate Mapping,FNH和NH的新成员 我想优化一个查询,以实现一对一的映射。实际上,我只想检索其中一个,其中Segment=0。PlantID、AreaID、CellID、DeviceID、StartDateTime构成数据的复合主键。将段添加到DataMore1和DataMore2的复合键 一个事件最多可以记录400个数据点…取决于他们选择的选项。 因此,我们选择将数据存储在单独的表中,以便在x天或x个月后清除不需要的数据 目标是通过FluentNHibernate做类似的事情 SELECT D

FNH和NH的新成员

我想优化一个查询,以实现一对一的映射。实际上,我只想检索其中一个,其中Segment=0。PlantID、AreaID、CellID、DeviceID、StartDateTime构成数据的复合主键。将段添加到DataMore1和DataMore2的复合键

一个事件最多可以记录400个数据点…取决于他们选择的选项。 因此,我们选择将数据存储在单独的表中,以便在x天或x个月后清除不需要的数据

目标是通过FluentNHibernate做类似的事情

SELECT        Data.PlantID, Data.AreaID, Data.CellID, Data.DeviceID, Data.StartDateTime, Data.DataPoint01, DataMore1.Segment, DataMore1.DataPoint101, 
                         DataMore2.DataPoint201
FROM            Data 
LEFT OUTER JOIN
                         DataMore1 ON Data.PlantID = DataMore1.PlantID AND Data.AreaID = DataMore1.AreaID AND Data.CellID = DataMore1.CellID AND 
                         Data.DeviceID = DataMore1.DeviceID AND Data.StartDateTime = DataMore1.StartDateTime AND **DataMore1.Segment = 0** 
LEFT OUTER JOIN
                         DataMore2 ON Data.PlantID = DataMore2.PlantID AND Data.AreaID = DataMore2.AreaID AND Data.CellID = DataMore2.CellID AND 
                         Data.DeviceID = DataMore2.DeviceID AND Data.StartDateTime = DataMore2.StartDateTime AND **DataMore2.Segment = 0**
模型

public class Data
{
        public virtual int PlantID { get; set; }
        public virtual int AreaID { get; set; }
        public virtual int CellID { get; set; }
        public virtual int DeviceID { get; set; }
        public virtual DateTime StartDateTime { get; set; }
        public virtual float DataPoint01 { get; set; }
        public virtual float DataPoint02 { get; set; }
        public virtual float DataPoint99 { get; set; }
        public virtual IEnumerable<DataMore1> DataMore1 { get; set; }
        public virtual IEnumerable<DataMore2> DataMore2 { get; set; }
}

public class DataMore1
{
        public virtual int PlantID { get; set; }
        public virtual int AreaID { get; set; }
        public virtual int CellID { get; set; }
        public virtual int DeviceID { get; set; }
        public virtual DateTime StartDateTime { get; set; }
        public virtual byte Segment { get; set; }
        public virtual float DataPoint101 { get; set; }
        public virtual float DataPoint102 { get; set; }
        public virtual float DataPoint199 { get; set;}
}

public class DataMore2
{
        public virtual int PlantID { get; set; }
        public virtual int AreaID { get; set; }
        public virtual int CellID { get; set; }
        public virtual int DeviceID { get; set; }
        public virtual DateTime StartDateTime { get; set; }
        public virtual byte Segment { get; set; }
        public virtual float DataPoint201 { get; set; }
        public virtual float DataPoint202 { get; set; }
        public virtual float DataPoint299 { get; set; }
}

那么,这是一个疑问问题

因为你是NH的新手,我给你的答案比要求的要宽泛一些。前两节课应该用自己的语言回答你的问题

public class DataQuery : AbstractQueryObject<IList<DataQueryResult>>
{
    public override IList<DataQueryResult> GetResult()
    {
        DataMore1 dm1 = null;
        DataMore2 dm2 = null;

        var list =
            this.Session.QueryOver<Data>()
                .JoinAlias(data => data.DataMore1, () => dm1, NHibernate.SqlCommand.JoinType.LeftOuterJoin, Expression.Eq("Segment", 0))
                .JoinAlias(data => data.DataMore2, () => dm2, NHibernate.SqlCommand.JoinType.LeftOuterJoin, Expression.Eq("Segment", 0))
                .Select(p =>
                    new DataQueryResult
                    {
                        PlantID = p.PlantID,
                        AreaID = p.AreaID,
                        CellID = p.CellID,
                        DeviceID = p.DeviceID,
                        StartDateTime = p.StartDateTime,
                        DataPoint01 = p.DataPoint01,
                        DataMore1Segment = dm1.Segment,
                        DataMore1DataPoint101 = dm1.DataPoint101,
                        DataMore2Segment = dm2.Segment,
                        DataMore2DataPoint201 = dm2.DataPoint201
                    })
                .List<DataQueryResult>();

        return list;   
    }
}

public class DataQueryResult
{
    internal DataQueryResult() { }

    public int PlantID { get; internal set; }
    public int AreaID { get; internal set; }
    public int CellID { get; internal set; }
    public int DeviceID { get; internal set; }
    public DateTime StartDateTime { get; internal set; }
    public float DataPoint01 { get; internal set; }
    public byte? DataMore1Segment { get; internal set; }
    public float? DataMore1DataPoint101 { get; internal set; }
    public byte? DataMore2Segment { get; internal set; }
    public float? DataMore2DataPoint201 { get; internal set; }
}

public abstract class AbstractQueryObject<TResult> : IQueryObject<TResult>
{
    protected ISession Session;

    public void Configure(object parameter)
    {
        /*obviously this NH query object implementation has to be provided with an ISession before it executes.
          for that purpose I have an generic repository which holds an ISession and exposes the method
          public interface IRepository { .. TResult ExecuteQuery<TResult>(IQueryObject<TResult> query); .. }
          and has the usual Save<T>/Delete<T> methods.
          obviously, to get the results you use: var data = repository.ExecuteQuery(new DataQuery());
          i like this pattern a lot, so forgive my promotion :)
          now, one repo instance keeps alive its session, so all entities from it are from the same isession. 
          when you dispose the repo, you kill the session. if you use DI in your classes, the repo instance is injected.
          very perky is that your classes depend on the iqo and irepo ifcs which means you can swap them for EF which sometimes we do:)
          easy unit testing.. etc.. */

        if (!(parameter is ISession))
            throw new ArgumentException("Argument of wrong type.");

        this.Session = parameter as ISession;
    }

    public abstract TResult GetResult();
}

public interface IQueryObject<TResult>
{
    void Configure(object parameter);

    TResult GetResult();
}
公共类数据查询:AbstractQueryObject
{
公共覆盖IList GetResult()
{
DataMore1 dm1=null;
DataMore2 dm2=null;
变量表=
this.Session.QueryOver()
.JoinAlias(data=>data.DataMore1,()=>dm1,NHibernate.SqlCommand.JoinType.LeftOuterJoin,Expression.Eq(“段”,0))
.JoinAlias(data=>data.DataMore2,()=>dm2,NHibernate.SqlCommand.JoinType.LeftOuterJoin,Expression.Eq(“段”,0))
.选择(p=>
新数据查询结果
{
PlantID=p.PlantID,
AreaID=p.AreaID,
CellID=p.CellID,
DeviceID=p.DeviceID,
StartDateTime=p.StartDateTime,
DataPoint01=p.DataPoint01,
DataMore1Segment=dm1.段,
DataMore1DataPoint101=dm1.DataPoint101,
DataMore2Segment=dm2.段,
DataMore2DataPoint201=dm2.DataPoint201
})
.List();
退货清单;
}
}
公共类DataQueryResult
{
内部DataQueryResult(){}
public int PlantID{get;internal set;}
公共int区域ID{get;内部集合;}
public int CellID{get;internal set;}
公共int设备ID{get;内部集合;}
公共日期时间StartDateTime{get;内部集合;}
公共浮点数据点01{get;内部集合;}
公共字节?DataMore1Segment{get;内部集合;}
公共浮点?DataMore1DataPoint101{get;内部集合;}
公共字节?DataMore2Segment{get;内部集合;}
公共浮点?DataMore2DataPoint201{get;内部集合;}
}
公共抽象类AbstractQueryObject:IQueryObject
{
受保护的会话;
公共void配置(对象参数)
{
/*显然,这个NH查询对象实现必须在执行之前提供ISession。
为此,我有一个通用存储库,它保存一个ISession并公开该方法
公共接口IRepository{..TResult ExecuteQuery(IQueryObject查询);…}
并具有常用的保存/删除方法。
显然,要获得结果,您需要使用:var data=repository.ExecuteQuery(new DataQuery());
我非常喜欢这种模式,所以请原谅我的晋升:)
现在,一个repo实例使其会话保持活动状态,因此它的所有实体都来自同一个会话。
当您处置repo时,您会终止会话。如果您在类中使用DI,则会注入repo实例。
非常令人振奋的是,您的类依赖于iqo和irepo IFC,这意味着您可以将它们交换为EF,我们有时会这样做:)
简单的单元测试…等等*/
如果(!(参数为ISession))
抛出新的ArgumentException(“类型错误的参数”);
this.Session=作为ISession的参数;
}
公共摘要TResult GetResult();
}
公共接口IQueryObject
{
void配置(对象参数);
TResult GetResult();
}

那么,这是一个查询问题

因为你是NH的新手,我给你的答案比要求的要宽泛一些。前两节课应该用自己的语言回答你的问题

public class DataQuery : AbstractQueryObject<IList<DataQueryResult>>
{
    public override IList<DataQueryResult> GetResult()
    {
        DataMore1 dm1 = null;
        DataMore2 dm2 = null;

        var list =
            this.Session.QueryOver<Data>()
                .JoinAlias(data => data.DataMore1, () => dm1, NHibernate.SqlCommand.JoinType.LeftOuterJoin, Expression.Eq("Segment", 0))
                .JoinAlias(data => data.DataMore2, () => dm2, NHibernate.SqlCommand.JoinType.LeftOuterJoin, Expression.Eq("Segment", 0))
                .Select(p =>
                    new DataQueryResult
                    {
                        PlantID = p.PlantID,
                        AreaID = p.AreaID,
                        CellID = p.CellID,
                        DeviceID = p.DeviceID,
                        StartDateTime = p.StartDateTime,
                        DataPoint01 = p.DataPoint01,
                        DataMore1Segment = dm1.Segment,
                        DataMore1DataPoint101 = dm1.DataPoint101,
                        DataMore2Segment = dm2.Segment,
                        DataMore2DataPoint201 = dm2.DataPoint201
                    })
                .List<DataQueryResult>();

        return list;   
    }
}

public class DataQueryResult
{
    internal DataQueryResult() { }

    public int PlantID { get; internal set; }
    public int AreaID { get; internal set; }
    public int CellID { get; internal set; }
    public int DeviceID { get; internal set; }
    public DateTime StartDateTime { get; internal set; }
    public float DataPoint01 { get; internal set; }
    public byte? DataMore1Segment { get; internal set; }
    public float? DataMore1DataPoint101 { get; internal set; }
    public byte? DataMore2Segment { get; internal set; }
    public float? DataMore2DataPoint201 { get; internal set; }
}

public abstract class AbstractQueryObject<TResult> : IQueryObject<TResult>
{
    protected ISession Session;

    public void Configure(object parameter)
    {
        /*obviously this NH query object implementation has to be provided with an ISession before it executes.
          for that purpose I have an generic repository which holds an ISession and exposes the method
          public interface IRepository { .. TResult ExecuteQuery<TResult>(IQueryObject<TResult> query); .. }
          and has the usual Save<T>/Delete<T> methods.
          obviously, to get the results you use: var data = repository.ExecuteQuery(new DataQuery());
          i like this pattern a lot, so forgive my promotion :)
          now, one repo instance keeps alive its session, so all entities from it are from the same isession. 
          when you dispose the repo, you kill the session. if you use DI in your classes, the repo instance is injected.
          very perky is that your classes depend on the iqo and irepo ifcs which means you can swap them for EF which sometimes we do:)
          easy unit testing.. etc.. */

        if (!(parameter is ISession))
            throw new ArgumentException("Argument of wrong type.");

        this.Session = parameter as ISession;
    }

    public abstract TResult GetResult();
}

public interface IQueryObject<TResult>
{
    void Configure(object parameter);

    TResult GetResult();
}
公共类数据查询:AbstractQueryObject
{
公共覆盖IList GetResult()
{
DataMore1 dm1=null;
DataMore2 dm2=null;
变量表=
this.Session.QueryOver()
.JoinAlias(data=>data.DataMore1,()=>dm1,NHibernate.SqlCommand.JoinType.LeftOuterJoin,Expression.Eq(“段”,0))
.JoinAlias(data=>data.DataMore2,()=>dm2,NHibernate.SqlCommand.JoinType.LeftOuterJoin,Expression.Eq(“段”,0))
.选择(p=>
新数据查询结果
{
PlantID=p.PlantID,
AreaID=p.AreaID,
CellID=p.CellID,
DeviceID=p.DeviceID,
StartDateTime=p.StartDateTime,
DataPoint01=p.DataPoint01,
DataMore1Segment=dm1.段,
DataMore1DataPoint101=dm1.DataPoint101,
DataMore2Segment=dm2.段,
DataMore2DataPoint201=dm2.DataPoint201
})
.List();
退货清单;
}
}
公共类DataQueryResult
{
内部DataQueryResult(){}
public int PlantID{get;internal set;}
公共int区域ID{get;内部集合;}
public int CellID{get;internal set;}
公共int设备ID{get;内部集合;}
公共日期时间StartDateTime{get;内部集合;}
公共浮点数据点01{get;内部集合;}
公共字节?DataMore1Segment{get;内部集合;}
公共浮点?DataMore1DataPoint101{get;内部集合;}
公共字节?DataMore2Segment{get;内部集合;}
公共浮点?DataMore2DataPoint201{get;内部集合;}
}
公共抽象类AbstractQ
var list = session.QueryOver<Data>()
                            .JoinAlias(data => data.DataMore1, () => dm1, NHibernate.SqlCommand.JoinType.LeftOuterJoin, Expression.Eq("Segment", (byte)0))
                            .JoinAlias(data => data.DataMore2, () => dm2, NHibernate.SqlCommand.JoinType.LeftOuterJoin, Expression.Eq("Segment", (byte)0))
                            .List<Data>()
                            });