1

New to FNH and NH.

I'd like to optimize a query for a OneToMany mapping. I'd actually like to only retrieve one of the many where Segment = 0. PlantID,AreaID,CellID,DeviceID,StartDateTime make up the composite primary key for Data. Add Segment to composite key for DataMore1 and DataMore2.

An event can record up to 400 data points...depending on the options they have chosen. So we've elected to store the data in separate tables for purging of unwanted data after x days or months.

The goal is to do something like this via 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**

The MODEL

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

And the MAPPINGS

  public DataMap()
 {
   Table("Data");
        CompositeId()
    .KeyProperty(e => e.PlantID)
    .KeyProperty(e => e.AreaID)
    .KeyProperty(e => e.CellID)
    .KeyProperty(e => e.DeviceID)
            .KeyProperty(e => e.StartDateTime);
        Map(e => e.DataPoint01);
        Map(e => e.DataPoint02);
        Map(e => e.DataPoint99);
        HasMany(e => e.DataMore1)
            .KeyColumns.Add("PlantID")
            .KeyColumns.Add("AreaID")
            .KeyColumns.Add("CellID")
            .KeyColumns.Add("DeviceID")
            .KeyColumns.Add("StartDateTime")
            .Cascade.All().Inverse();
        HasMany(e => e.DataMore2)
            .KeyColumns.Add("PlantID")
            .KeyColumns.Add("AreaID")
            .KeyColumns.Add("CellID")
            .KeyColumns.Add("DeviceID")
            .KeyColumns.Add("StartDateTime")
            .Cascade.All().Inverse();
}

public DataMore1Map()
{
    Table("DataMore1");
    CompositeId()
        .KeyProperty(e => e.PlantID)
        .KeyProperty(e => e.AreaID)
        .KeyProperty(e => e.CellID)
        .KeyProperty(e => e.DeviceID)
        .KeyProperty(e => e.StartDateTime)
        .KeyProperty(e => e.Segment);
    Map(e => e.DataPoint101);
    Map(e => e.DataPoint102);
    Map(e => e.DataPoint199);
}

public DataMore2Map()
{
    Table("DataMore2");
    CompositeId()
        .KeyProperty(e => e.PlantID)
        .KeyProperty(e => e.AreaID)
        .KeyProperty(e => e.CellID)
        .KeyProperty(e => e.DeviceID)
        .KeyProperty(e => e.StartDateTime)
        .KeyProperty(e => e.Segment);
    Map(e => e.DataPoint201);
    Map(e => e.DataPoint202);
    Map(e => e.DataPoint299);
}
4

2 回答 2

1

所以,这是一个查询问题?

由于您是新罕布什尔州的新手,因此我给出的答案比要求的要宽一些。前两节课应该自己回答你的问题。

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();
}
于 2013-07-26T07:57:46.307 回答
0

对已接受答案的这种修改使我到达了我想去的地方。结果是一个选择语句,它只返回我需要的东西......

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>()
                            });
于 2013-07-26T19:01:44.673 回答