2009-06-15 18 views
5

Sto lavorando con un database precedente che utilizza chiavi composite. E sto cercando di usare NHibernate per inserire un nuovo record nel database. NHibernate specifica che devo creare l'ID manualmente, ma quando provo ad inserire con questo ID ottengo il messaggio:Inserimento di un record con una chiave composta utilizzando NHibernate

System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'tablename' when IDENTITY_INSERT is set to OFF. 

non posso toccare una qualsiasi delle impostazioni db come sono amministrati da sede centrale negli Stati Uniti.

ho scoperto che posso fare un inserto db tramite:

insert into tablename (tablename_country_id, /*extra fields here*/) values (16, /*extra values here*/) 

e la colonna tablename_id viene automaticamente incrementato.

E 'possibile scrivere una sorta di gestore che mi consente di creare un oggetto ID con il set CountryId e farlo incrementare automaticamente la proprietà Id.

Cheers.


Esempio di codice:

Tabella Definizione:

CREATE TABLE [dbo].[tablename](
    [tablename_country_id] [int] NOT NULL, 
    [tablename_id] [int] IDENTITY(1,1) NOT NULL, 

    -- more fields here 

    CONSTRAINT [pk_tablename] PRIMARY KEY 
    (
     [tablename_country_id] ASC, 
     [tablename_id] ASC 
    ) 
) 

Classe Files:

public class ModelObject 
{ 
    public ID { get; set; } 
    // more properties here 
} 

public class ID : INHibernateProxy 
{ 
    public int Id { get; set; } 
    public int CountryId { get; set; } 
    public ILazyInitializer HibernateLazyInitializer { get { throw new ApplicationException(); } } 
} 

Mapping File:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model" assembly="API"> 
    <class name="ModelObject" table="dbname.dbo.tablename" lazy="false"> 
     <composite-id name="Id" class="ID"> 
      <key-property name="Id" column="tablename_id" type="int" /> 
      <key-property name="CountryId" column="tablename_country_id" type="int" /> 
     </composite-id> 
     <!-- more properties here --> 
    </class> 
</hibernate-mapping> 

risposta

0

Penso di poter impostare una colonna Identity su una delle tue chiavi nella chiave composta.

So che in fluentnhibernate ho un nome di colonna di identità per una chiave

+0

In che modo ciò influisce sulla memorizzazione nella cache degli oggetti? In particolare la 'session.Get (id);' con la possibilità di duplicati nella colonna 'tablename_id'. – zonkflut

+0

questa opzione genera un FKUnmatchingColumnsException 'deve avere lo stesso numero di colonne della chiave primaria di riferimento' – zonkflut

0

omposite forse questo può funzionare. Se si aggiunge esplicitamente la dichiarazione di aggiornamento, anche se è necessario cambiarlo in uno sProc o qualcosa del genere che è possibile.

https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/querysql.html#querysql-cud 

qui è un esempio del concetto sproc.

<class name="Person"> 
    <id name="id"> 
     <generator class="increment"/> 
    </id> 
    <property name="name" not-null="true"/> 
    <sql-insert>exec createPerson ?, ?</sql-insert> 
    <sql-delete>exec deletePerson ?</sql-delete> 
    <sql-update>exec updatePerson ?, ?</sql-update> 
</class> 
0

ho capito che non si può modificare la tabella di database o vincoli, ma sono assolutamente sicuro che gli oggetti di database in realtà implica che si deve utilizzare una chiave composta NHibernate?

Una chiave composita NHibernate deve essere utilizzata per le tabelle in cui l'unicità di una riga è determinata da più di una colonna. Nell'esempio che hai fornito, risulta che l'univocità di ogni riga è in realtà determinata solo dalla singola colonna tablename_id. La chiave primaria risulta superflua: cioè, non può essere violata perché uno dei suoi elementi costitutivi è una colonna di identità che sarà sempre diversa.

Forse la chiave primaria è stata collocata lì dai colleghi per qualche altro motivo (indicizzazione, ecc.).

Ciò significa che la mappatura di NHibernate deve realmente collassare in qualcosa di abbastanza semplice: un POCO normale con un ID singolo che si collega a tablename_id utilizzando un semplice generatore di ID nativo di NHibernate. La proprietà CountryID quindi unisce le proprietà ellisse come una proprietà normale per raggiungere l'obiettivo: CountryID è impostato con ID auto-incrementato dal database.

public class ModelObject 
{ 
    public int ID { get; set; } 
    public int CountryID { get; set; } 
    // more properties here 
} 

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model" assembly="API"> 
    <class name="ModelObject" table="dbname.dbo.tablename" lazy="false"> 
     <id name="ID" column="tablename_id" type="int"> 
     <generator class="native" /> 
    </id> 
     <property name="CountryID" column="tablename_country_id" type="int" /> 
     <!-- more properties here --> 
    </class> 
</hibernate-mapping> 
+0

il CountryID è richiesto poiché viene utilizzato per identificare in modo univoco quale istanza del database (ovvero il database di quel paese) è in replica. Questa era la soluzione originale scelta per gestire i database distribuiti. Quindi per rimanere corretto devo usare la chiave composta :( – zonkflut

0

come notato in fluent nhibernate auto increment non key (Id) property, può non essere necessario utilizzare una chiave composta per ottenere la natura generato del campo. Considerare l'utilizzo di questo o simile a:

Mappa (x => x.Field) .Colonna ("Campo"). Generated.Avvisi(). ReadOnly();

Problemi correlati