【问题标题】:Nhibernate doing updates on select?Nhibernate对选择进行更新?
【发布时间】:2010-01-04 18:34:30
【问题描述】:

我有以下课程:

public class Product
{
  public virtual Guid Id { get; set; }
  public virtual string Name { get; set; }
  public virtual Decimal PricePerMonth { get; set; }
  public virtual BillingInterval DefaultBillingInterval { get; set; }
  public virtual string AdditionalInfo { get; set; }
}

映射如下所示:

 <class name="Product" table="Products">
    <id name="Id" column="ProductId">
      <generator class="guid.comb"/>
    </id>
    <property name="Name" column="ProductName" not-null="true" type="String" />
    <property name="PricePerMonth" column="PricePerMonth" not-null="true" type="Decimal" />
    <property name="DefaultBillingInterval" type="int" not-null="true" />
    <property name="AdditionalInfo" type="string" not-null="false" />
</class>

我使用Repository&lt;T&gt; 类和以下方法(Session 是返回当前会话的属性):

public IEnumerable<T> FindAll(DetachedCriteria criteria)
{
  return criteria.GetExecutableCriteria(Session).List<T>();
}

现在当我执行以下操作时(会话与存储库中使用的会话相同):

IEnumerable<ProductDTO> productDTOs = null;
using(ITransaction tx = session.BeginTransaction(IsolationLevel.ReadCommitted))
{
    var products = repository.FindAll(new DetachedCriteria.For<Product>().Add(Restrictions.Like("Name", "Some Product%")));
    productDTOs = ToDTOs(products);
    tx.Commit();
}
// Do stuff with DTO's

提交语句在那里,因为我使用了一个服务层,如果没有发生错误,它会自动提交每个事务。我只是在这里折叠了我的服务层以便于可视化..

我的 ToDTOs 方法只是转换为 DTO:

private IEnumerable<ProductDTO> ToDTO(IEnumerable<Product> products)
{
  return products.Select(x => new ProductDTO()
    {
      Id = x.Id,
      Name = x.Name,
      PricePerMonth = x.PricePerMonth,
      AdditionalInfo = x.AdditionalInfo
    }).ToList();
}

我的休眠日志显示以下输出:

2010-01-04 19:13:11,140 [4] DEBUG NHibernate.SQL - SELECT ... From Products ...
2010-01-04 19:13:11,237 [4] DEBUG NHibernate.SQL - UPDATE Products ...
2010-01-04 19:13:11,548 [4] DEBUG NHibernate.SQL - UPDATE Products ...
...

因此,通过选择产品,它会为会话提交时返回的每个产品发出更新语句,即使产品中没有任何更改..

有什么想法吗?

【问题讨论】:

  • 真的实体是如何实现的吗?我不相信你。
  • 它是...确实,我有一个附加产品的订单列表,但我已经从类和映射中删除了这个列表(如这里所示),它是同样的结果..我的困惑更加深刻,因为这不会发生在我的其他实体身上..

标签: c# .net nhibernate nhibernate-mapping


【解决方案1】:

只有当我有一个实体返回的属性值与分配给它的值不同时,我才会产生这种效果。然后被 NH 视为脏。

例子:

class Foo
{
  private string name;

  public string Name 
  { 
    // does not return null when null had been set
    get { return name ?? "No Name"; }
    set { name = value; }
  }

}

这就是我编写映射文件的方式。

<class name="Product" table="Products">
    <id name="Id" column="ProductId">
      <generator class="guid.comb"/>
    </id>
    <property name="Name" column="ProductName" not-null="true" />
    <property name="PricePerMonth" not-null="true" />
    <property name="DefaultBillingInterval" not-null="true" />
    <property name="AdditionalInfo" />
</class>

您不需要指定类型。它们由 NHibernate 在运行时确定。

【讨论】:

  • 啊哈,所以它一定是导致问题的 BillingInterval 枚举,因为它被映射为 int?如何在不发生更新语句的情况下映射枚举(由 int 支持)?
  • 映射枚举时不需要指定任何类型。
  • 即使数据库将 DefaultBillingInterval 存储为 smallint(枚举值具有整数值 3、6、12),这是否有效?
  • 试试吧……还有一个sql-type属性,大概只有CreateSchema需要。
  • 如果我使用 FluentNhibernate,我将如何解决这个问题
【解决方案2】:

较早的帖子,但也许这会对以后的人有所帮助。

我有一个 Data Repository C# 类库(Oracle 作为数据库)。表值为 NULL,但在我的回购中,该值被定义为十进制,应该是?十进制。运行选择时修复了此更新问题。

【讨论】:

  • 另一种可能会导致意外更新的情况是,新属性已添加到数据库映射中,并且从使用旧版本映射创建的数据库中读取记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
相关资源
最近更新 更多