【问题标题】:Queryover with restriction on different class than the return class对与返回类不同的类进行限制的查询
【发布时间】:2014-01-15 13:10:47
【问题描述】:

对于我当前的项目,我正在学习 NHibernate,但我无法翻译以下查询

select person.Firstname, person.Lastname
from Person
    inner join Contract         on contract.PersonId =      person.Id
    inner join Budget           on budget.ContractId =      contract.Id
    inner join Choice           on choice.BudgetId =        budget.Id
    inner join ChosenBenefit    on ChosenBenefit.ChoiceId = choice.Id
where ChosenBenefit.BenefitImplementationId = 77

我认为下面的方法可以解决问题,但我得到了一个空引用,其中包含我无法从中做出正面或反面的堆栈跟踪。

Choice choice = null;
Budget budget = null;
Contract contract = null;
Person person = null;

var peopleThatChose = Session.QueryOver<ChosenBenefit>()
            .JoinAlias(chosenBenefit => chosenBenefit.Choice, () => choice)
            .JoinAlias(chosenBenefit => choice.Budget, () => budget)
            .JoinAlias(chosenBenefit => budget.Contract, () => contract)
            .JoinAlias(chosenBenefit => contract.Person, () => person)
        .Where(chosenBenefit => chosenBenefit.BenefitImplementation.Id == 77)
        .Select(benefit => person);

从各地的所有示例来看,我应该QueryOver&lt;Person&gt;,但我无法找到我想要限制的地方。

我错过了什么?

【问题讨论】:

  • 是否有从PersonChosenBenefit 的映射?
  • 没有。由于两者之间没有直接联系,我不确定我将如何实现它。
  • 抱歉我打错了——我想问一下是否有从PersonContract的映射。
  • 是的,一个人有很多合同。

标签: c# .net nhibernate


【解决方案1】:

假设你的映射有一些事情,我很确定你可以在没有子查询的情况下做到这一点:

Person person = null;

var peopleThatChose =
    Session.QueryOver<Person>(() => person)
        .JoinQueryOver<Contract>(person => person.Contracts)
        .JoinQueryOver<Budget>(contract => contract.Budget)
        .JoinQueryOver<Choice>(budget => budget.Choice)
        .JoinQueryOver<ChosenBenefit>(choice => choice.ChosenBenefit)
            .Where(chosen => chosen.BenefitImplementation.Id == 77)
        .SelectList(list => list
            .Select(() => person.FirstName)
            .Select(() => person.LastName))
        .List<object[]>();

【讨论】:

  • 是的,这正是我希望找到的。干净简单。
【解决方案2】:

如果我正确阅读了您的模型:Person 可能有更多合同(contract.PersonId)。所以在这种情况下我们要做的就是将查询分成两部分。

  1. 子查询,从合约中获取PerosnId(按Benefit过滤)和
  2. 仅检索 Persons 的 Person 外部查询...

1) 子查询

 var subquery = Session.QueryOver<ChosenBenefit>()
         // the path from Benefit to Contract is the same
        .JoinAlias(chosenBenefit => chosenBenefit.Choice, () => choice)
        .JoinAlias(chosenBenefit => choice.Budget, () => budget)
        .JoinAlias(chosenBenefit => budget.Contract, () => contract)

    // we do filter over choosen benefit, to get correct contracts
    .Where(chosenBenefit => chosenBenefit.BenefitImplementation.Id == 77)

     // lets select the PerosnId from a contract
    .Select(benefit => contract.PersonId);

2) 现在我们将查询 Person,并使用子查询结果进行过滤(在 DB 服务器上)

var peopleThatChose = session.QueryOver<Person>()
    .WithSubquery
    .WhereProperty(p => p.Id)
    .In(subquery);

那么,我们做了什么:

  • 我们使用从ChoosenBenefitContract...的多对一导航来获得PersonId
  • 我们用结果过滤了纯 Person 查询,现在我们甚至可以对 Person 实体进行适当的分页(Take()、Skip())

【讨论】:

  • 那么,我必须将我的直接连接查询重新表述为查询中的位置?
  • 正如我所说,如果我理解正确的话……我们有一个拥有许多合同的人。如果这是真的:是的,将查询转换为外部查询和子查询 - 如上所示。如果我错了,并且 realtion 一直是多对一的......它可能是一个查询,正如我们在我的答案中用子查询表示的那样。在那里,我们确实从一个开始(受益)选择了最远端的合同......我上面建议的是通常的方法来调整一个项目,它确实有一个集合。这样我们真的可以实现很多,主要是分页
  • 如果您后来意识到,您的结果计数正在增长超过预期的人员计数(使用 Andrew 方法),我会说,子查询方法可能会有所帮助。无论如何,祝 NHibernate Boris 好运 ;)
  • 没有。我要说的是,如果您有一个人,有 2 个合同 .... both 导致收益 77,您将在列表中有两次此人。因为这开始导致笛卡尔积。我知道您喜欢 Andrew 解决方案,因为它又好又简单。但是 (我现在会很粗鲁) 这是错误的解决方案。你说你来自 SQL 世界……我相信你知道我在说什么……
  • 啊,是的,我现在明白你的意思了。我曾希望 NHibernate 对此很聪明;)我将不得不对此进行调查。感谢您的更新
猜你喜欢
  • 2013-07-06
  • 2017-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-26
  • 2014-12-28
相关资源
最近更新 更多