【问题标题】:Problem with NHibernateNHibernate 的问题
【发布时间】:2010-04-16 04:53:05
【问题描述】:

我正在尝试获取共享该类别的产品列表。

NHibernate 不返回错误的产品。

这是我的 Criteria API 方法:

public IList<Product> GetProductForCategory(string name)
        {

            return _session.CreateCriteria(typeof(Product))
                .CreateCriteria("Categories")
                .Add(Restrictions.Eq("Name", name))
                .List<Product>();

        }

这是我的 HQL 方法:

public IList<Product> GetProductForCategory(string name)
        {
            return _session.CreateQuery("select from Product p, p.Categories.elements c where c.Name = :name").SetString("name",name).List<Product>();


        }

这两种方法在应该返回 2 个产品时都不返回任何产品。

这是 Product 类的映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="CBL.CoderForTraders.DomainModel" namespace="CBL.CoderForTraders.DomainModel">
  <class name="Product" table="Products" >
    <id name="_persistenceId" column="ProductId" type="Guid" access="field" unsaved-value="00000000-0000-0000-0000-000000000000">
      <generator class="assigned" />
    </id>
    <version name="_persistenceVersion" column="RowVersion" access="field" type="int" unsaved-value="0" />

    <property name="Name" column="ProductName" type="String" not-null="true"/>
    <property name="Price" column="BasePrice" type="Decimal" not-null="true" />
    <property name="IsTaxable" column="IsTaxable" type="Boolean" not-null="true" />
    <property name="DefaultImage" column="DefaultImageFile" type="String"/>

    <bag name="Descriptors" table="ProductDescriptors">
      <key column="ProductId" foreign-key="FK_Product_Descriptors"/>
      <one-to-many class="Descriptor"/>
    </bag>
    <bag name="Categories"  table="Categories_Products" >
      <key column="ProductId" foreign-key="FK_Products_Categories"/>
      <many-to-many class="Category" column="CategoryId"></many-to-many>
    </bag>

    <bag name="Orders" generic="true" table="OrderProduct" >
      <key column="ProductId" foreign-key="FK_Products_Orders"/>
           <many-to-many column="OrderId" class="Order" />
    </bag>


  </class>
</hibernate-mapping>

最后是 Category 类的映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="CBL.CoderForTraders.DomainModel" namespace="CBL.CoderForTraders.DomainModel" default-access="field.camelcase-underscore" default-lazy="true">

  <class name="Category" table="Categories" >
    <id name="_persistenceId" column="CategoryId" type="Guid" access="field" unsaved-value="00000000-0000-0000-0000-000000000000">
      <generator class="assigned" />
    </id>
    <version name="_persistenceVersion" column="RowVersion" access="field" type="int" unsaved-value="0" />

    <property name="Name" column="Name" type="String" not-null="true"/>
    <property name="IsDefault" column="IsDefault" type="Boolean" not-null="true" />
    <property name="Description" column="Description" type="String" not-null="true" />

    <many-to-one name="Parent" column="ParentID"></many-to-one>

    <bag name="SubCategories" inverse="true">
      <key column="ParentID" foreign-key="FK_Category_ParentCategory" />
      <one-to-many class="Category"/>
    </bag>
    <bag name="Products" table="Categories_Products">
      <key column="CategoryId" foreign-key="FK_Categories_Products" />
      <many-to-many column="ProductId" class="Product"></many-to-many>
    </bag>
  </class>
</hibernate-mapping>

你能看出可能是什么问题吗?

如果我删除添加行我的查询是:

return _session.CreateCriteria(typeof(Product))
                .CreateCriteria("Categories")
                .List<Product>();

现在查看我的监视窗口,我返回了 5 个附加了类别的产品。 我在初始查询中查找的类别名称出现在 2 个产品上。

所以当我添加该行时出现了问题: .Add(Restrictions.Eq("Name", name))

这是生成的包含限制行的 Sql:

NHibernate:选择 this_.ProductId 作为 ProductId23_1_、this_.RowVersion 作为 RowVersion23_1_、this_.ProductName 作为 ProductN3_23_1_、this_.BasePrice 作为 BasePrice23_1_、this_.IsTaxable 作为 IsTaxable23_1_、this_.DefaultImageFile 作为 DefaultI6_23_1_、categories3_.ProductId 作为 ProductId、category1_。 CategoryId 作为 CategoryId, category1_.CategoryId 作为 CategoryId16_0_, category1_.RowVersion 作为 RowVersion16_0_, category1_.Name 作为 Name16_0_, category1_.IsDefault 作为 IsDefault16_0_, category1_.Description 作为 Descript5_16_0_, category1_.ParentID 作为 ParentID16_0_ FROM Products this_inner join Categories_Products categories3_ on this_.ProductId =categories3_.ProductId 内连接 Categories category1_ on categories3_.CategoryId=category1_.CategoryId WHERE category1_.Name = @p0; @p0 = 'Momemtum'

【问题讨论】:

  • 你应该发布生成的sql
  • sql 对我来说看起来不错。您确定 Categories_Products 表的数据正确吗?
  • 是的。在监视窗口我可以看到数据
  • 如果问题,我认为,是在你坚持的类(或实例化和存储它们的代码),那么我不能给你一个最终的解决方案。 看一下数据库中的数据,我很确定Categories_Products中缺少一些东西

标签: nhibernate nhibernate-mapping hql criteria-api


【解决方案1】:

仅从查询和映射很难说。您如何创建数据也很有趣。

HQL 实际上应该是这样的:

select p
from Product p join p.Categories c 
where c.Name = :name

假设您在数据库中的数据是正确的,这应该可行。

顺便说一句,您可以(应该)在同一个表中映射产品和类别之间的双向多对多关系,因为它很可能是相同的数据。只需将其映射到同一个表/列并建立一对多关系之一inverse="true"

您需要确保两个集合同步更新。如果您只将产品添加到类别中,则产品中缺少链接。维护模型的一致性不是 NHibernate 的责任。

要查找这样的错误:

  • 看一下生成的SQL(在配置中将show_sql设置为true。你会在控制台看到它。)你在使用SqlServer的时候,也可以使用Profiler。
  • 在 SQL 控制台中执行查询。
  • 查看数据库中的数据。

【讨论】:

  • 如果我认为问题出在您坚持的课程中,那么我无法为您提供解决方案。
【解决方案2】:

您的 Criteria 查询看起来不错 - 就像我写的几十个一样。

问题在于您的多对多链接表。

Product 映射中你有这个:

<bag name="Categories"  table="Categories_Products" >
  <key column="ProductId" foreign-key="FK_Products_Categories"/>
  <many-to-many class="Category" column="CategoryId"></many-to-many>
</bag>

Category 映射中,你有这个:

<bag name="Products" table="Categories_Products">
  <key column="CategoryId" foreign-key="FK_Categories_Products" />
  <many-to-many column="ProductId" class="Product"></many-to-many>
</bag>

在我看来,您好像颠倒了外键,将 ProductId 链接到 FK_Products_Categories 而不是 FK_Categories_Products

我发现在这种情况下有用的是打开 NHibernate 的 SQL 日志记录,然后查看生成的 SQL。通常这会给我一个关于我的映射错误的很大线索。更多信息,请参阅Configure Log4Net for use with NHibernate

【讨论】:

    【解决方案3】:

    真的对不起各位。我的映射和代码很好。问题是名称参数。

    【讨论】:

      【解决方案4】:

      尝试使用分离条件的子查询以生成与以下普通 sql 等效的内容

      select * from Products where ProductId in (select distinct cp.ProductId from Categories_Products cp inner join Categories c on cp.CategoryId = c.CategoryId and c.Name = name)
      

      类似这样的...

      DetachedCriteria subCriteria = DetachedCriteria.For(typeof(Category))
          .SetResultTransformer(new DistinctRootEntityResultTransformer())
          .SetProjection(Projections.Property("Category.Products.ProductId"))
          .Add(Restrictions.PropertyEq("Name", name));
      
      return _session.CreateCriteria.For(typeof(Product))
          .Add(Subqueries.PropertyIn("ProductId", subCriteria))
          .List<Product>();
      

      Ack,Category.Products.ProductId 可能不正确,但也许您可以看到我在此处尝试执行的操作并找出要在子查询中使用的正确投影。

      【讨论】:

      • 我收到以下错误消息:TestCase 'ProductPersistenceTests._Setup.CanGetProductsForCategory._TearDown' 失败:无法解析属性:Category.Products.ProductId of:CBL.CoderForTraders.DomainModel.Category NHibernate.QueryException消息:无法解析属性:CBL.CoderForTraders.DomainModel.Category 的 Category.Products.ProductId
      猜你喜欢
      • 2010-11-17
      • 2011-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-29
      • 2011-08-31
      相关资源
      最近更新 更多