Вставка записи с составным ключом с использованием NHibernate

Я работаю с устаревшей базой данных, в которой используются составные ключи. И я пытаюсь использовать NHibernate для вставки новой записи в базу данных. NHibernate указывает, что мне нужно создать идентификатор вручную, но когда я пытаюсь вставить с этим идентификатором, я получаю сообщение:

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

Я не могу коснуться каких-либо настроек базы данных, поскольку они администрируются головным офисом в США.

Я обнаружил, что могу вставить db через:

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

и столбец tablename_id автоматически увеличивается.

Можно ли написать какой-то обработчик, который позволяет мне создавать объект ID с набором CountryId и автоматически увеличивать свойство Id.

Ваше здоровье.


Пример кода:

Определение таблицы:

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

Файлы класса:

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

Файл сопоставления:

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

person zonkflut    schedule 15.06.2009    source источник


Ответы (4)


Я думаю, вы можете установить столбец идентификатора для одного из ваших ключей в составном ключе.

я знаю, что в fluentnhibernate у меня есть имя столбца идентификатора для составного ключа

person Chen Kinnrot    schedule 15.06.2009
comment
Как это повлияет на кеширование объектов? В частности session.Get<TModel>(id); с возможностью дублирования в столбце tablename_id. - person zonkflut; 16.06.2009
comment
этот параметр вызывает исключение FKUnmatchingColumnsException: «должно иметь такое же количество столбцов, что и указанный первичный ключ» - person zonkflut; 16.06.2009

возможно, это может сработать. Если вы явно добавляете оператор обновления, также если вам нужно изменить его на sProc или что-то в этом роде, вы можете.

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

вот пример концепции 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>
person Bluephlame    schedule 16.06.2009

Я понимаю, что вы не можете изменить таблицу или ограничения базы данных, но абсолютно ли вы уверены, что объекты базы данных действительно подразумевают, что вы должны использовать составной ключ NHibernate?

Составной ключ NHibernate следует использовать для тех таблиц, в которых уникальность строки определяется более чем одним столбцом. В приведенном вами примере оказывается, что уникальность каждой строки фактически определяется только одним столбцом tablename_id. Первичный ключ оказывается лишним: то есть его нельзя нарушить, потому что один из составляющих его элементов является столбцом идентичности, который всегда будет другим.

Возможно, первичный ключ был помещен туда вашими коллегами по какой-то другой причине (индексация и т. Д.).

Это означает, что ваше отображение NHibernate должно действительно свернуться до чего-то довольно простого: обычного POCO с одним отображением идентификатора в tablename_id с использованием простого генератора собственных идентификаторов NHibernate. Свойство CountryID затем присоединяется к вашим свойствам как обычное свойство для достижения вашей цели: CountryID устанавливается с идентификатором, автоматически увеличиваемым базой данных.

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>
person Andy Grout    schedule 09.09.2009
comment
CountryID требуется, поскольку он используется для однозначной идентификации того, какой экземпляр базы данных (т.е. база данных какой страны) находится в репликации. Это было оригинальное решение, выбранное для работы с распределенными базами данных. Следовательно, чтобы оставаться верным, я должен использовать составной ключ :( - person zonkflut; 15.09.2009

как указано в свойство fluent nhibernate auto increment без ключа (Id), возможно, нет необходимости использовать составной ключ, чтобы получить сгенерированный характер поля. Рассмотрите возможность использования этого или аналогичного:

Карта (x => x.Field) .Column ("Поле"). Generated.Always (). ReadOnly ();

person mcfea    schedule 07.07.2014