2009-06-15 12 views
5

Je travaille avec une base de données existante qui utilise des clés composites. Et j'essaie d'utiliser NHibernate pour insérer un nouvel enregistrement dans la base de données. NHibernate précise que je dois créer l'ID manuellement, mais lorsque je tente d'insérer cette id je reçois le message:Insertion d'un enregistrement avec une clé composite à l'aide de NHibernate

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

Je ne peux pas toucher les paramètres db car ils sont administrés par le siège social aux Etats-Unis.

Je trouve que je peux faire un insert db via:

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

et la colonne tablename_id est automatiquement incrémentée.

Est-il possible d'écrire une sorte de gestionnaire qui me permet de créer un objet ID avec l'ensemble CountryId et d'avoir auto-incrémenter la propriété Id.

Cheers.


Exemple de code:

Tableau Définition:

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 
    ) 
) 

Class 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(); } } 
} 

fichier de mappage:

<?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> 

Répondre

0

Je pense que vous pouvez définir une colonne d'identité à l'une de vos clés dans la clé composite.

je sais que j'ai fluentnhibernate un nom de colonne d'identité pour une clé he de la dentine

+0

Comment cela affectera la mise en cache des objets? En particulier le 'session.Get (id);' avec la possibilité de doublons dans la colonne 'tablename_id'. – zonkflut

+0

cette option lance une FKUnmatchingColumnsException « doit avoir le même nombre de colonnes que la clé primaire référencée » – zonkflut

0

peut-être cela peut fonctionner. Si vous ajoutez explicitement l'instruction de mise à jour, Aussi, si vous avez besoin de le changer en sProc ou quelque chose comme ça, vous pouvez le faire.

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

Voici un exemple du concept 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

Je comprends que vous ne pouvez pas modifier la table de base de données ou des contraintes, mais êtes-vous absolument sûr que les objets de base de données implique vraiment que vous devez utiliser une clé composite NHibernate?

Une clé composite NHibernate doit être utilisée pour les tables où l'unicité d'une ligne est déterminée par plusieurs colonnes. Dans l'exemple que vous avez fourni, l'unicité de chaque ligne n'est en réalité déterminée que par la seule colonne tablename_id. La clé primaire s'avère superflue: c'est-à-dire qu'elle ne peut pas être violée car l'un de ses éléments constitutifs est une colonne d'identité qui sera toujours différente.

Peut-être que la clé primaire a été placée là par vos collègues pour une autre raison (indexation, etc.).Cela signifie que votre mappage NHibernate devrait vraiment se réduire à quelque chose de très simple: un POCO normal avec un seul identifiant mappant tablename_id en utilisant un simple générateur d'identificateur natif NHibernate. La propriété CountryID joint ensuite vos propriétés ellided comme une propriété normale pour réaliser votre objectif: CountryID est défini avec l'ID auto-incrémenté par la base de données.

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

le CountryID est nécessaire, car il est utilisé pour identifier de manière unique l'instance de la base de données (à savoir que la base de données de pays), il est sur la réplication. Il s'agissait de la solution d'origine choisie pour traiter les bases de données distribuées. Par conséquent, pour rester correct, je dois utiliser la clé composite :( – zonkflut

0

comme indiqué dans fluent nhibernate auto increment non key (Id) property, il ne peut pas être nécessaire d'utiliser une clé composite pour obtenir la nature du produit sur le terrain. Pensez à utiliser ceci ou similaire à:..

Carte (x => x.Field) .Column ("Champ") Generated.Always() ReadOnly();