NHibernate comparison constraint to a coalesced date

纵然是瞬间 提交于 2019-12-11 12:15:37

问题


There is a great Q/A to prefacing this question here: NHibernate COALESCE issue

I need to be able to compare a date object to a date value from within an inner join. The unfamiliar territory here has been the implementation of this COALESCE along with the date LT constraint

Here is my current SQL query

SELECT DISTINCT Sites.*
FROM Sites
 INNER JOIN Sites_WF_Info
       ON Site_Key = SiteWFInfo_Site_Key
       AND SiteWFInfo_Effective_Date <= @today
       AND @today <= SiteWFInfo_End_Date
 INNER JOIN Profit_Centers
       ON Site_Key = ProfCtr_Site_Key
       AND ProfCtr_Open_Date <= @today
       AND @today < Coalesce(ProfCtr_Close_Date, '6/6/2079')

What I would like to know is how to go about using a constant in place of the ExpenseReport.PeriodFrom property ==> left.

Ideally, I would like to set left/right

// DateTime effDate is passed in
var left = Projections.Property<DateTime>(effDate);
var right = Projects.SqlFunction("COALESCE",
            NHibernateUtil.DateTime,
            Projections.Constant(DateTime.Parse("6/6/2079").Date, NHibernateUtil.DateTime),
            Projections.Property<ProfitCenter>(pc => pc.CloseDate));

Then, when the restriction is invoked

var restriction = Restrictions.LtProperty(left, right);

So that when I build the QueryOver<> I can substitute this restriction object for one of the Where clauses

var foo = CurrentSession().QueryOver<Site>(() => sa)
    .Inner.JoinQueryOver<ProfitCenter>(() => pca)
    .Where(restriction)

THE FINAL ANSWER

This required the introduction of a new 'flattened' domain 'ResultModel' (SiteWithWindowsTimezoneId) so that I could return a more specific model from my query and avoid lazy loading all the other stuff that is currently associated with Site. This new query style has turned a 16+ sql query method down to a single query. The savings was worth the time. Thanks again for your help. I hope that this gist is helpful to someone in the future.

SiteWorkforceInfo swia = null;
SiteWorkforceConfig swcfg = null;
ProfitCenter pca = null;
Site sa = null;
SiteWithWindowsTimezoneId siteResult = null;

var leftProfCloseDate = Projections.Constant(effectiveDate);
var rightProfCloseDate = Projections.SqlFunction("COALESCE", 
    NHibernateUtil.DateTime, 
    Projections.Property<ProfitCenter>(pc => pc.CloseDate),
    Projections.Constant(DateTime.Parse("6/6/2079").Date, NHibernateUtil.DateTime)
);

var profCloseDateRestriction = Restrictions.LtProperty(leftProfCloseDate, rightProfCloseDate);

var activeSites = CurrentSession().QueryOver<SiteWorkforceInfo>(() => swia)
    .Inner.JoinQueryOver<Site>(() => swia.Site, () => sa)
    .Left.JoinQueryOver<SiteWorkforceConfig>(() => sa.SiteWFConfig, () => swcfg)
    .Inner.JoinQueryOver<ProfitCenter>(() => sa.ProfitCenters, () => pca)
    .Where(() => swia.EffectiveDate <= effectiveDate)
    .Where(() => effectiveDate <= swia.EndDate)
    .Where(() => pca.OpenDate <= effectiveDate)
    .Where(profCloseDateRestriction)
    .Where(() => swia.TimeCaptureRule > 0)
    .SelectList(
        list => list
            .Select(() => sa.Key).WithAlias(() => siteResult.Key)
            .Select(() => sa.Id).WithAlias(() => siteResult.Id)
            .Select(() => sa.IdFormatted).WithAlias(() => siteResult.IdFormatted)
            .Select(() => sa.Description).WithAlias(() => siteResult.Description)
            .Select(() => swcfg.WindowsTimezoneId).WithAlias(() => siteResult.WindowsTimezoneId)
                )
    .TransformUsing(Transformers.AliasToBean<SiteWithWindowsTimezoneId>())
    .List<SiteWithWindowsTimezoneId>();

return activeSites;

--- The Resulting query ---

SELECT sa1_.Site_Key as y0_, 
    sa1_.Site_Id as y1_, 
    sa1_.Site_Id_Formatted as y2_, 
    sa1_.Site_Description as y3_, 
    swcfg2_.SiteWFCfg_Windows_Timezone_Id as y4_ 
FROM Sites_WF_Info this_ 
inner join Sites sa1_ 
    on this_.SiteWFInfo_Site_Key=sa1_.Site_Key 
inner join Profit_Centers pca3_ 
    on sa1_.Site_Key=pca3_.ProfCtr_Site_Key 
left outer join Sites_WF_Configuration swcfg2_ 
    on sa1_.Site_Key=swcfg2_.SiteWFCfg_Site_Key 
WHERE this_.SiteWFInfo_Effective_Date <= @p0 
    and @p1 <= this_.SiteWFInfo_End_Date 
    and pca3_.ProfCtr_Open_Date <= @p2 
    and @p3 < coalesce(pca3_.ProfCtr_Close_Date, @p4) 
    and this_.SiteWFInfo_TimeCapRule_Key > @p5

回答1:


If I do understand correctly, we need to replace the left (currently property projection) with the effDate constant projection. Then we can do it like this

// instead of this
// var left = Projections.Property<DateTime>(effDate);

// we would use this
// DateTime effDate is passed in
var effDate = DateTime.Today.Date; // C#'s today
var left = Projections.Constant(effDate);

And also, we should switch (change the order) of our "COALESCE", because the property should go first: Coalesce(ProfCtr_Close_Date, '6/6/2079')

var right = Projects.SqlFunction("COALESCE",
    NHibernateUtil.DateTime,

    // As DOC of COALESCE says:
    // "Evaluates the arguments in order and returns the current value of 
    //  the first expression that initially does not evaluate to NULL."

    Projections.Property<ProfitCenter>(pc => pc.CloseDate), 
    Projections.Constant(DateTime.Parse("6/6/2079").DateNHibernateUtil.DateTime)
    );

Finally, we should use the same alias for the joined columns. Let's adjust main query a bit:

var foo = CurrentSession().QueryOver<Site>(() => sa)
    .Inner.JoinQueryOver<ProfitCenter>(() =>  sa.ProfitCenter, () => pca)
    .Where(restriction)

And the right side should use pca as well

var right = Projects.SqlFunction("COALESCE",
    NHibernateUtil.DateTime,
    // be sure that column goes to correct table
    // ==> use the same alias
    Projections.Property(() => pca.CloseDate), 
    Projections.Constant(DateTime.Parse("6/6/2079").DateNHibernateUtil.DateTime)
    );


来源:https://stackoverflow.com/questions/29221666/nhibernate-comparison-constraint-to-a-coalesced-date

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!