【问题标题】:How to retrieve entities from a join using QueryOver in NHibernate如何在 NHibernate 中使用 QueryOver 从连接中检索实体
【发布时间】:2012-04-16 23:05:15
【问题描述】:

我正在尝试从 QueryOver 查询中返回多个实体。我在纯文本编辑器中编写此代码,因此可能存在语法错误,但它应该可以理解。

public class Product
{
    public virtual int ID { get; set; }
    public virtual string ProductName { get; set; }
    public virtual List<Category> Categories { get; set; }
    public virtual List<Inventory> Inventories { get; set; }
    ...
}

public class Category
{
    public virtual int ID { get; set; }
    public virtual string CategoryName { get; set; }
    public virtual string Style { get; set; }
    public virtual Product Product { get; set; }
    ...
}

public class Inventory
{
    public virtual int ID { get; set; }
    public virtual List<Discount> Discounts { get; set; }
    public virtual Product Product { get; set; }
    public virtual bool InStock { get; set; }
    ...
}

public class Discount
{
    public virtual int ID { get; set; }
    public virtual Inventory Inventory { get; set; }
    public virtual decimal DiscountAmount { get; set; }
    ...
}

现在我的目标是在单个查询中使用产品 ID 和其他几个选项来拉回 Category、Inventory 和 DiscountAmount。我已经通过这个查询使用 HQL 来实现它:

var query = session.CreateQuery("select category, inventory, discount.DiscountAmount"
    + " from Product product"
    + " join product.Categories category"
    + " join product.Inventories inventory"
    + " left join inventory.Discounts discount"
    + " where product.ID = :productID"
    + " and category.Style = :style"
    + " and inventory.InStock = 1");

通过这个查询,我得到一个对象数组列表,每个对象数组都有一个 Category 实体、Inventory 实体和一个 DiscountAmount 小数。我的目标是使用 QueryOver 查询来执行相同的查询而不使用魔法字符串,但我无法让它工作。到目前为止,这是我尝试过的:

Product productAlias = null;
Category categoryAlias = null;
...
var query = session.QueryOver<Product>(() => productAlias)
    .Where(() => productAlias.ID == productID)
    .JoinAlias(() => productAlias.Categories, () => categoryAlias)
    ...
    .Select(Projections.Property(() => categoryAlias.ID),
        Projections.Property(() => discountAlias.Inventory),
        Projections.Property(() => discount.DiscountAmount));

此查询仅拉回 Category 的 ID,虽然它确实拉回了完整的 Inventory 实体,但它使用完整的附加数据库查询来获取它。

    ...
    .Select(Projections.Property(() => categoryAlias),
        Projections.Property(() => inventoryAlias),
        Projections.Property(() => discountAlias.DiscountAmount));

此查询引发“无法解析属性:categoryAlias of : Product”的运行时异常。

    ...
    .Select(Projections.Property(() => categoryAlias.ID).WithAlias(() => ReturnClass.Category),
        Projections.Property(() => inventoryAlias.ID).WithAlias(() => ReturnClass.Inventory),
        Projections.Property(() => discountAlias.DiscountAmount).WithAlias(() => ReturnClass.DiscountAmount))
    .TransformUsing(Transformers.AliasToBean<ReturnClass>());

此查询引发“Int32 类型的对象无法转换为类别类型”的运行时异常。

    ...
    .Select(Projections.Property(() => categoryAlias.ID)
    .TransformUsing(Transformers.AliasToBean<Category>())

此查询返回一个默认类别实体。

那么有什么方法可以使用 QueryOver API 来模拟 HQL 查询,还是我唯一的选择是在 HQL 或进行多个查询之间进行选择?

编辑:更清楚地说,我真的想尽可能地避免使用魔法字符串,所以我真的更喜欢强类型的 QueryOver 查询。目前我正在使用一个 QueryOver 查询,它返回 Category 和 Inventory 实体的 ID,然后分别查询它们,但由于无论如何我必须在第一个查询中点击这些表,我宁愿一次性返回它们。

编辑 2:我想要实现的确切 SQL 是

Select Category.ID, Category.CategoryName, Category.Style, (other Category columns),
Inventory.ID, Inventory.InStock, (other Inventory columns),
Discount.DiscountAmount
From Products as Product
Inner join Categories as Category ...
Where Product.ID = @productID
And Category.Style = @style
And ...

【问题讨论】:

    标签: nhibernate queryover


    【解决方案1】:

    我认为你应该使用 Fetch 而不是 JoinAlias:

    .Fetch(product => product.Categories).Eager
    

    不要使用 select:.List&lt;Product&gt;() // 然后通过 LINQ 你可以从 Product 中获取类别和库存

    【讨论】:

    • 这不是要撤回与该产品相关的所有类别和库存实体吗?这比我需要的数据多得多。我已经可以从查询中访问我需要的特定 Category 和 Inventory 实体,只需将它们拉回到同一个查询中即可。 HQL 查询正是这样做的,我试图将它与 QueryOver 匹配。我正在寻找的确切 SQL 是:选择 Category.ID、Category.Style、(其他 Category 列)、Inventory.ID、Inventory.InStock、(其他 Inventory 列)、Discount.DiscountAmount From Products Product inner join ...其中 Product.ID = ...
    • 有几种方法可以做到这一点。使用 QueryOver 您可以使用 JoinAlias 或 JoinQueryOver 而不是它不会遍历整个图。或者,如果做得对,就不应该这样做。我使用未来查询。
    【解决方案2】:

    所以这里是一个“渴望”为我的类别加载所有子类别的示例。 迭代类别集合时没有 N+1。未来是关键。

    Category catalias = null;
    
    
            var subCategories =_session.QueryOver<Category>().JoinQueryOver(x => x.SubCategories, () => catalias, JoinType.LeftOuterJoin).
                Future<Category>();
    
            var categories = _session.QueryOver<Category>().Where(x => x.ParentCategoryId == null).Future<Category>();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多