【问题标题】:nhibernate queryover with complex join over non-related entitiesnhibernate queryover 与非相关实体的复杂连接
【发布时间】:2013-02-14 12:28:04
【问题描述】:

所以我在过去的几个小时里一直在寻找答案,但我似乎找不到任何有意义的东西。

public class Game
{
   public virtual Guid ID { get; set; }
   public virtual ResultStructure Structure { get; set; }
   public virtual List<Result> Results { get; set; }
}

public class Result
{
  public virtual Player Player { get; set; }
  public virtual int Position { get; set; }
}

public class ResultStructure
{
  public virtual Guid ID { get; set; }
  public virtual List<ResultOutcomes> Outcomes { get; set;}
}

public class ResultOutcomes
{
  public virtual int Position { get; set; }
  public virtual int Points { get; set; }
}

public class PlayerSummary
{
  public virtual Player Player { get; set; }
  public virtual int Points { get; set; }
}

我要做的是获取玩家列表以及他们在众多不同游戏中获得的积分(game 上方有多个包含游戏列表的实体)。所以查询的最终结果将是 List&lt;PlayerSummary&gt; 我正在寻找的 SQL 看起来像这样:

SELECT p.*, Sum(rs.points) FROM result r
  JOIN player p on r.playerid = p.id
  JOIN game g on r.gameid = g.id
  JOIN resultstructure rs on g.resultstructureid = rs.id
  JOIN resultoutcomes ro on rs.id = ro.resultstructureid AND ro.position = r.position

注意,我还需要对结构实体进行一些查询/求和,这就是包含它的原因。

我正在尝试使用 NHibernate 执行此操作,使用 TypeSafe 的东西,我的计划是让应用程序与数据库无关,所以我不能使用直接 SQL(目前它使用 Postgres,但我可能会转向 SQL服务器)。

我不想在你使用那些魔术字符串的地方使用“HQL”的东西,所以我尝试使用 Linq 或 QueryOver/Query。

谁能指出我正确的方向?

【问题讨论】:

  • 这是您应该使用 HQL 的确切情况。 “魔弦”并不是你想的那样。
  • 我真的想要类型安全的东西,我确实了解 HQL ish,我很欣赏它可能会满足我的需要,但我想保持一切不变,我在大多数情况下使用查询。
  • @DiegoMijelshon 我已经添加了我的解决方案,能否详细说明为什么我应该使用 HQL 而不是我提出的解决方案?
  • 您的方法存在几个问题。首先,您使用的是QueryOver,而不是Query。后者不需要显式连接。其次,HQL 会为您提供更简洁的查询(比您的 SQL 代码更少),因此“保持一切相同”不是一个好的理由。第三,HQL 是类型安全的;您将类型安全与智能感知混淆了。
  • 我使用的代码与我在 SQL 中编写的查询一样干净(排除位置选择在 Where 子句中的问题)。我的印象是 TypeSafe 与确保在编译时标记实体名称更改有关,据我所知,它在 HQL 中没有。

标签: c# linq nhibernate queryover


【解决方案1】:

在我的情况下似乎上述情况是可能的,因为有关系,只是不直接。

您可以使用JoinAlias

基本区别在于,使用JoinAlias,您可以将多个表连接到同一个基表,而与JoinQueryOver 一样,它通过将每个表仅连接到前一个表的表进行线性推进。

所以查询看起来像这样。

Result resultAlias = null;
ResultOutcome outcomeAlias = null;
ResultStructure structureAlias = null;

var results = Session.QueryOver(() => resultAlias) // Assigns resultAlias so it can be used further in the query.
   .Inner.JoinQueryOver(x => x.Game) // returns a QueryOver Game so you can do a where on the game object, or join further up the chain.
   .Inner.JoinAlias(x => x.ResultStructure, () => structureAlias) // joins on the Structure table but returns the QueryOver for the Game, not the structure.
   .Inner.JoinAlias(() => structureAlias.Outcomes, () => outcomeAlias) // same again for the outcomes
   .Where(() => resultAlias.Position == outcomeAlias.Position)
   .Select(
        Projections.Group(() => resultAlias.Player),
        Projections.Sum(() => outcomeAlias.Points)
   );

这应该给人们这个想法。这样做的缺点是对“位置”的限制不会发生在 Join 上,而是发生在 Where 子句中。我很高兴收到任何可以选择这样做的人的来信,因为这会迫使数据库查询规划器沿着特定的路线前进。

仍在处理转换和排序,但这让我更进一步。

【讨论】:

  • 既然都是内连接,那么额外连接条件的放置位置应该没关系...对吧?
  • 虽然它们并不都加入“结果”,但从编码的角度来看确实很重要。 JoinAlias 可能无关紧要,您不能将 ResultStructure JoinAlias 放在 JoinQueryOver 之前,因为它会尝试加入 Result 而不是 Game。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多