【问题标题】:NHibernate comparison constraint to a coalesced dateNHibernate 对合并日期的比较约束
【发布时间】:2015-03-23 22:31:08
【问题描述】:

这里有一个很好的问答来解决这个问题: NHibernate COALESCE issue

我需要能够将日期对象与内部联接中的日期值进行比较。这里不熟悉的领域是这个 COALESCE 的实现以及日期 LT 约束

这是我当前的 SQL 查询

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')

我想知道的是如何使用常量代替 ExpenseReport.PeriodFrom 属性 ==> left。

理想情况下,我想设置左/右

// 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));

然后,当调用限制时

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

这样当我构建 QueryOver 时,我可以用这个 restriction 对象替换 Where 子句之一

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

最终答案

这需要引入一个新的“扁平化”域“ResultModel”(SiteWithWindowsTimezoneId),以便我可以从查询中返回更具体的模型,并避免延迟加载当前与 Site 关联的所有其他内容。这种新的查询样式已将 16+ sql 查询方法变为单个查询。节省的时间是值得的。再次感谢您的帮助。我希望这个要点对将来的某人有所帮助。

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;

--- 结果查询 ---

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

【问题讨论】:

    标签: c# nhibernate queryover nhibernate-criteria


    【解决方案1】:

    如果我理解正确,我们需要将left (当前属性投影) 替换为effDate 常量投影。那我们就可以这样做了

    // 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);
    

    而且,我们应该切换 (更改顺序) 我们的“COALESCE”,因为属性应该首先出现: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)
        );
    

    最后,我们应该为连接的列使用相同的别名。让我们稍微调整一下主查询:

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

    右侧也应该使用pca

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

    【讨论】:

    • Projections.Constant!谢谢你。我更新了上面的 SQL 查询,现在包含了 SiteWorkforceInfo 表。这个有点奇怪,因为站点域模型没有像引用利润中心那样引用 SiteWorkforceInfo(s)。目前,我正在尝试从 SiteWorkforceInfo 实体开始构建查询。
    • 万一,SiteWorkforceInfo 没有被站点域引用......它几乎不会起作用。原因是,NHibernate 可以执行与映射中的设置相关的 JOIN。换句话说,除了来自映射中定义的关系(多对一,一对多)之外,我们不能创建任何其他JOIN。但这真的会成为简单扩展模型的问题吗?并创建这样的参考?
    • 正在处理它......“老板”不喜欢在核心中引入额外的“临时”模型......这个越来越长;)
    • 无论如何,祝您在 NHibernate 上好运。相信我,这是一个很棒的工具。如果以后有任何事情......请在这里询问;)享受NHiberante,先生!
    • 啊啊啊啊,成功了!事实证明,我们在核心中引入了一个新的 ResultModel 命名空间,并为团队开发了一种新模式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 2018-08-26
    • 2016-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    相关资源
    最近更新 更多