2009-04-22 49 views
1

我一直在試圖讓Nhibernate使用字節 數組作爲版本映射到sql時間戳。我實現了一個 IUserVersionType,但Nhibernate正在數據庫 中創建varbinary而不是時間戳。受Ayende最近在博客文章 併發性的啓發,我改變了我的映射,以指定sql-type到時間戳 完美運行。然而,我現在面臨一個相當好奇的問題 其中Nhibernate做插入,獲取新版本,然後 立即嘗試進行更新並嘗試設置版本 列,這是一個SQL時間戳失敗。作爲版本的NHibernate和sql時間戳列

這是我的映射:

<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
assembly="Core.Domain, Version=0.1.3397.31993, Culture=neutral, 
PublicKeyToken=94dc7dc697cfcfc0" namespace="Core.Domain.Entities" 
default-lazy="false"> 
<class name="Contact" table="Contacts" xmlns="urn:nhibernate- 
mapping-2.2" optimistic-lock="version" dynamic-insert="true" dynamic- 
update="true"> 
    <id name="Id" type="Int32" column="Id"> 
    <generator class="identity" /> 
    </id> 
    <version name="Version" type="BinaryBlob" generated="always" 
unsaved-value="null"> 
    <column name="Version" sql-type="timestamp" not-null="false" /> 
    </version> 
    <property name="Title" type="String"> 
    <column name="Title" length="5" /> 
    </property> 
    <property name="FirstName" type="String"> 
    <column name="FirstName" not-null="true" length="50" /> 
    </property> 
    <property name="MiddleName" type="String"> 
    <column name="MiddleName" length="50" /> 
    </property> 
    <property name="LastName" type="String"> 
    <column name="LastName" not-null="true" length="50" /> 
    </property> 
    <property name="Suffix" type="String"> 
    <column name="Suffix" length="5" /> 
    </property> 
    <property name="Email" type="String"> 
    <column name="Email" length="50" /> 
    </property> 
    <bag name="PhoneNumbers" inverse="true" cascade="all-delete- 
orphan"> 
    <key foreign-key="FK_Contacts_PhoneNumbers_ContactId" on- 
delete="cascade" column="ContactId" /> 
    <one-to-many class="Core.Domain.Entities.PhoneNumber, 
Core.Domain, Version=0.1.3397.31993, Culture=neutral, 
PublicKeyToken=94dc7dc697cfcfc0" /> 
    </bag> 
    <property name="DateCreated" type="DateTime"> 
    <column name="DateCreated" /> 
    </property> 
    <property name="DateModified" type="DateTime"> 
    <column name="DateModified" /> 
    </property> 
    <property name="LastModifiedBy" type="String"> 
    <column name="LastModifiedBy" /> 
    </property> 
</class> 
</hibernate-mapping> 
<?xml version="1.0" encoding="utf-8"?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
assembly="Core.Domain, Version=0.1.3397.31993, Culture=neutral, 
PublicKeyToken=94dc7dc697cfcfc0" namespace="Core.Domain.Entities" 
default-lazy="false"> 
<class name="Customer" table="Customers" xmlns="urn:nhibernate- 
mapping-2.2" optimistic-lock="version" dynamic-insert="true" dynamic- 
update="true"> 
    <id name="Id" type="Int32" column="Id"> 
    <generator class="identity" /> 
    </id> 
    <version name="Version" type="BinaryBlob" generated="always" 
unsaved-value="null"> 
    <column name="Version" sql-type="timestamp" not-null="false" /> 
    </version> 
    <property name="AccountNumber" access="nosetter.pascalcase- 
underscore" type="String"> 
    <column name="AccountNumber" unique="true" length="25" /> 
    </property> 
<!-- other mappings... --> 
    <property name="DateCreated" type="DateTime"> 
    <column name="DateCreated" /> 
    </property> 
    <property name="DateModified" type="DateTime"> 
    <column name="DateModified" /> 
    </property> 
    <property name="LastModifiedBy" type="String"> 
    <column name="LastModifiedBy" /> 
    </property> 
    <joined-subclass name="Core.Domain.Entities.Individual, 
Core.Domain, Version=0.1.3397.31993, Culture=neutral, 
PublicKeyToken=94dc7dc697cfcfc0" table="Individuals"> 
    <key column="CustomerId" /> 
    <many-to-one fetch="join" lazy="false" not-null="true" 
cascade="all" unique="true" not-found="exception" name="Contact" 
column="ContactID" /> 
    <bag name="Addresses" table="Addresses_Individuals"> 
     <key column="AddressId" foreign- 
key="FK_Addresses_Individuals_Addresses_AddressId" /> 
     <many-to-many column="IndividualId" 
class="Core.Domain.Entities.Address, Core.Domain, 
Version=0.1.3397.31993, Culture=neutral, 
PublicKeyToken=94dc7dc697cfcfc0" foreign- 
key="FK_Addresses_Individuals_Individuals_IndividualId" /> 
    </bag> 
    </joined-subclass> 
    <joined-subclass name="Core.Domain.Entities.Store, Core.Domain, 
Version=0.1.3397.31993, Culture=neutral, 
PublicKeyToken=94dc7dc697cfcfc0" table="Stores"> 
    <key column="CustomerId" /> 
    <many-to-one unique="true" cascade="save-update" fetch="join" 
not-null="true" not-found="exception" name="Address" 
column="AddressId" /> 
    <many-to-one lazy="proxy" not-null="true" cascade="all" not- 
found="exception" name="Client" column="ClientId" /> 
    <property name="StoreName" type="String"> 
     <column name="StoreName" not-null="true" length="50" /> 
    </property> 
    <bag name="Contacts" table="Contacts_Stores"> 
     <key column="ContactId" foreign- 
key="FK_Contacts_Stores_Contacts_ContactId" /> 
     <many-to-many column="StoreId" 
class="Core.Domain.Entities.Contact, Core.Domain, 
Version=0.1.3397.31993, Culture=neutral, 
PublicKeyToken=94dc7dc697cfcfc0" foreign- 
key="FK_Contacts_Stores_Stores_StoreId" /> 
    </bag> 
    </joined-subclass> 
</class> 
</hibernate-mapping> 

與相關聯繫的個體呼叫Session.Save導致 以下錯誤:

NHibernate: INSERT INTO Addresses (Line1, PostalCode, Country, 
DateCreated, DateModified, LastModifiedBy) VALUES (@p0, @p1, @p2, @p3, 
@p4, @p5); select SCOPE_IDENTITY(); @p0 = 'Order Address Line 1', @p1 
= 'CV31 6BW', @p2 = 'United Kingdom', @p3 = '20/04/2009 19:45:32', @p4 
= '20/04/2009 19:45:32', @p5 = '' 
NHibernate: SELECT address_.Version as Version22_ FROM Addresses 
address_ WHERE [email protected]; @p0 = '1' 
NHibernate: INSERT INTO Contacts (FirstName, LastName, DateCreated, 
DateModified, LastModifiedBy) VALUES (@p0, @p1, @p2, @p3, @p4); select 
SCOPE_IDENTITY(); @p0 = 'Joe', @p1 = 'Bloggs', @p2 = '20/04/2009 
19:45:34', @p3 = '20/04/2009 19:45:34', @p4 = '' 
NHibernate: SELECT contact_.Version as Version33_ FROM Contacts 
contact_ WHERE [email protected]; @p0 = '1' 
NHibernate: INSERT INTO Customers (AccountNumber, DateCreated, 
DateModified, LastModifiedBy) VALUES (@p0, @p1, @p2, @p3); select 
SCOPE_IDENTITY(); @p0 = '', @p1 = '20/04/2009 19:45:34', @p2 = 
'20/04/2009 19:45:34', @p3 = '' 
NHibernate: INSERT INTO Individuals (ContactID, CustomerId) VALUES 
(@p0, @p1); @p0 = '1', @p1 = '1' 
NHibernate: SELECT individual_1_.Version as Version2_ FROM Individuals 
individual_ inner join Customers individual_1_ on 
individual_.CustomerId=individual_1_.Id WHERE 
[email protected]; @p0 = '1' 
NHibernate: UPDATE Contacts SET Version = @p0 WHERE Id = @p1 AND 
Version = @p2; @p0 = 'System.Byte[]', @p1 = '1', @p2 = 'System.Byte[]' 

System.Data.SqlClient.SqlException: Cannot update a timestamp column. 
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, 
Boolean breakConnection) 
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException 
exception, Boolean breakConnection) 
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning 
(TdsParserStateObject stateObj) 
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, 
SqlCommand cmdHandler, SqlDataReader dataStream, 
BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject 
stateObj) 
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader 
ds, RunBehavior runBehavior, String resetOptionsString) 
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds 
(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean 
returnStream, Boolean async) 
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior 
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String 
method, DbAsyncResult result) 
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery 
(DbAsyncResult result, String methodName, Boolean sendToPipe) 
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 
at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) 
in c:\CSharp\NH\nhibernate\src\NHibernate\AdoNet\AbstractBatcher.cs: 
line 203 
at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object 
id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] 
includeProperty, Int32 j, Object oldVersion, Object obj, 
SqlCommandInfo sql, ISessionImplementor session) in c:\CSharp\NH 
\nhibernate\src\NHibernate\Persister\Entity 
\AbstractEntityPersister.cs: line 2713 
NHibernate.Exceptions.GenericADOException: could not update: 
[Core.Domain.Entities.Contact#1][SQL: UPDATE Contacts SET Version = 
@p0 WHERE Id = @p1 AND Version = @p2] 

任何想法,爲什麼NHibernate的嘗試更新的版本列 聯繫人,即使它沒有爲地址?

回答

2

我發現,使用動態插入=上導致此問題沿着類「真」。我成功使用以下映射:

... 
    <class name="Contact" table="Contact"> 
     <id name="ID" column="ID" type="int"> 
      <generator class="identity" /> 
     </id> 
     <version name="Version" generated="always" unsaved-value="null" type="BinaryBlob"/> 
... 
2

該地址沒有我假設的版本列。

我想知道你從哪裏得到sql-type。爲什麼不這樣呢?

<version name="Version" type="Timestamp" generated="always" unsaved-value="null"> 
    <column name="Version" not-null="false" /> 
    </version> 

您需要的課程在實體日期時間。

+0

Address確實有一個版本列。 我不能使用上面的映射,因爲我需要利用SQL Server的二進制日期時間數據類型,而不是日期時間。 – Jimit 2009-04-25 18:16:21

+0

我不知道,不知道這個工程。我建議你在NHibernate的用戶組(http://groups.google.com/group/nhusers)上詢問Ayende自己,或者在Ayendes博客上發表評論。 – 2009-04-25 18:59:27