我一直在关注NHibernate夏季系列。到目前为止一切都很好,一切都按预期工作,即使我使用NHibernate 3.1并且视频使用版本1.2。
然而,我刚遇到一个问题,对我来说这似乎是一个巨大的错误。我现在在第3节,我们在数据库中插入,更新和删除客户。这是Customer类:
public class Customer
{
private int customerId;
private string firstName;
private string lastName;
public virtual int CustomerId
{
get { return customerId; }
set { customerId = value; }
}
public virtual string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public virtual string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
这是映射文件:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="DataTransfer" assembly="DataTransfer">
<class name="DataTransfer.Customer, DataTransfer" table="Customer">
<id name="CustomerId" column="CustomerId" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="FirstName" column="FirstName" type="string" length="50" not-null="false" />
<property name="LastName" column="LastName" type="string" length="50" not-null="false" />
</class>
</hibernate-mapping>
配置文件不是太花哨:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.OdbcDriver</property>
<property name="connection.connection_string">Dsn=datasource;uid=user</property>
<property name="dialect">NHibernate.Dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping assembly="DataTransfer"></mapping>
</session-factory>
</hibernate-configuration>
现在问题就在于此。当我像这样插入一个新客户时:
public int AddCustomer(Customer customer)
{
int newId = (int)session.Save(customer);
session.Flush();
return newId;
}
newId总是等于零,即使insert语句成功,customer.Id也永远不会更新为数据库生成的标识值,因为我可以在数据库中看到新客户。当我使用NHibernate 3.1
时会发生这种情况但是,如果我将projet的引用更改为NHibernate 1.2而不更改单行代码,newId将包含实际插入的Id和customer.Id将更新。
我想知道NHibernate 3.1的这种奇怪的行为是否正常,或者我是否必须做一些特别的工作,就像我期望的那样,但对我来说,它看起来像一个bug。
答案 0 :(得分:3)
从NHibernate 2.1.2开始,您必须在显式NHibernate事务中包装所有数据库交互(甚至是查询)。有一个复杂的边缘情况列表可以做到这一点,但现在只需要相信这是事实。因此,此示例中应使用的典型模式需要类似于以下代码段:
public int AddCustomer(Customer customer)
{
int newId;
using(var tx = session.BeginTransaction())
{
newId = (int)session.Save(customer);
tx.Commit();
}
return newId;
}
在NH 2.1.2之前,NH提供了隐式交易,如果您没有明确说明它们,但肯定在NH 3.1下,您需要明确关于NH交易边界。请注意,在上面的示例中,tx.Commit()调用会隐式刷新会话(假设您尚未修改FlushMode的默认设置)。