代码之家  ›  专栏  ›  技术社区  ›  Jimit

nHibernate和SQL时间戳列作为版本

  •  1
  • Jimit  · 技术社区  · 15 年前

    我一直在绞尽脑汁想让NHibernate处理一个字节 数组作为版本映射到SQL时间戳。我已经实施了 iuserversiontype但nhibernate正在数据库中创建varbinary 而不是时间戳。灵感来源于Ayende最近的一篇博文 并发性,我更改了映射以将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>
    

    调用会话。保存在具有关联联系人结果的个人上 出现以下错误:

    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 address_.Id=@p0; @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 contact_.Id=@p0; @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
    individual_.CustomerId=@p0; @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要更新版本栏吗? 为了联系,即使不是为了地址?

    3 回复  |  直到 15 年前
        1
  •  2
  •   Scott M    15 年前

    我发现在类上使用dynamic insert=“true”会导致这个问题。我成功地使用了以下映射:

    ...
        <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
  •  2
  •   Stefan Steinegger    15 年前

    我想地址没有版本列。

    我想知道SQL类型是从哪里来的。为什么不走这边?

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

    当然,您需要实体中的日期时间。