NHibernate: Использование Fluent Nhibernate для сохранения дочерних объектов - PullRequest
19 голосов
/ 08 февраля 2009

В моей системе у меня есть две сущности - ShoppingCart и ShoppingCartItem. Довольно общий вариант использования. Однако, когда я сохраняю свою ShoppingCart, ни один из элементов не сохраняется в БД.

Внутри моего объекта я создаю новый объект ShoppingCart.

ShoppingCart cart = CreateOrGetCart();

Затем я добавляю в начало существующий Продукт, полученный из базы данных.

cart.AddItem(product);

Это просто оболочка для добавления элемента в IList.

    public virtual void AddItem(Product product)
    {
        Items.Add(new ShoppingCartItem { Quantity = 1, Product = product });
    }

Затем я вызываю SaveOrUpdate в репозитории

Repository.SaveOrUpdate(cart);

Что выглядит так:

   public T SaveOrUpdate(T entity)
    {
        Session.SaveOrUpdate(entity);
        return entity;
    }

Я использую Fluent NHibernate для отображения:

    public ShoppingCartItemMap()
    {
        WithTable("ShoppingCartItems");

        Id(x => x.ID, "ShoppingCartItemId");
        Map(x => x.Quantity);

        References(x => x.Cart, "ShoppingCartId").Cascade.SaveUpdate();
        References(x => x.Product, "ProductId");
    }


    public ShoppingCartMap()
    {
        WithTable("ShoppingCarts");

        Id(x => x.ID, "ShoppingCartId");
        Map(x => x.Created);
        Map(x => x.Username);

        HasMany<ShoppingCartItem>(x => x.Items)
            .IsInverse().Cascade.SaveUpdate()
            .WithKeyColumn("ShoppingCartId")
            .AsBag();
    }

Схема базы данных (SQL Server 2005) также довольно общая:

CREATE TABLE [dbo].[ShoppingCarts]
(
[ShoppingCartID] [int] NOT NULL IDENTITY(1, 1),
[Username] [nvarchar] (50) NOT NULL,
[Created] [datetime] NOT NULL
)
GO
ALTER TABLE [dbo].[ShoppingCarts] ADD CONSTRAINT [PK_ShoppingCarts] PRIMARY KEY CLUSTERED ([ShoppingCartID])
GO



CREATE TABLE [dbo].[ShoppingCartItems]
(
[ShoppingCartItemId] [int] NOT NULL IDENTITY(1, 1),
[ShoppingCartId] [int] NOT NULL,
[ProductId] [int] NOT NULL,
[Quantity] [int] NOT NULL
)
GO
ALTER TABLE [dbo].[ShoppingCartItems] ADD CONSTRAINT [PK_ShoppingCartItems] PRIMARY KEY CLUSTERED ([ShoppingCartItemId])
GO
ALTER TABLE [dbo].[ShoppingCartItems] ADD CONSTRAINT [FK_ShoppingCartItems_Products] FOREIGN KEY ([ProductId]) REFERENCES [dbo].[Products] ([ProductId])
GO
ALTER TABLE [dbo].[ShoppingCartItems] ADD CONSTRAINT [FK_ShoppingCartItems_ShoppingCarts] FOREIGN KEY ([ShoppingCartId]) REFERENCES [dbo].[ShoppingCarts] ([ShoppingCartID])
GO

Когда я сохраняю или обновляю свою ShoppingCart, почему не сохраняются также все ShoppingCartItems?

Пожалуйста, помогите.

Спасибо

Ben

UPDATE: Обернуть его в транзакцию, предоставив мне дополнительную информацию:

Невозможно вставить значение NULL в столбец ShoppingCartId таблицы. 'WroxPizza.dbo.ShoppingCartItems'; столбец не допускает пустых значений. Вставить не удается. Заявление было прекращено.

Это потому, что это новая корзина.

Ответы [ 8 ]

3 голосов
/ 06 марта 2009

У меня была именно эта проблема с беглым nhibernate. Кажется, есть небольшая ошибка в отображении отношений один-ко-многим, и отношения не сохраняются автоматически или каскадно. См. Здесь сообщение о группе Fluent NHibernate .

Очевидно, кто-то работает над проблемой!

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

2 голосов
/ 13 февраля 2009

Почему вы включили .Cascade.SaveUpdate() в строку

References(x => x.Cart, "ShoppingCartId").Cascade.SaveUpdate()

Возможно, это сбивает с толку NHibernate (или Fluent NHibernate), что, похоже, происходит каскадное сохранение / обновление с обоих концов ваших отношений?

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

1 голос
/ 08 февраля 2009

Попробуйте обернуть Session.SaveOrUpdate в транзакцию или принудительно сбросить сразу после.

0 голосов
/ 27 декабря 2010

Как вы заметили, вы определили (в схеме базы данных) поля с Identity, поэтому эти поля должны быть установлены в файле карты. Пример как следующий:

Id(x => x.ID, "ShoppingCartItemId").GeneratedBy.Identity();

ошибка, которую вы получаете, потому что вы не установили поля Identity в отображении для генерации Identity, поэтому при попытке сохранить () столбец Identity не генерируется (и в нем устанавливается значение NULL) базы данных), то выдает ошибку.

0 голосов
/ 13 марта 2009

Проблема с вашим оператором конфигурации sessionfactory. Не используйте Exposeconfiguration, если вы хотите, чтобы ваши данные сохранялись. Это, безусловно, решит вашу проблему с сохранением данных.

0 голосов
/ 08 февраля 2009

Возможно ли, что ваша корзина сначала сохраняет, а затем корзину? следовательно, у дочерних элементов нет родительского идентификатора для использования?

Вы МОЖЕТЕ явным образом сохранить корзину обратно в БД при создании, затем добавить в нее элементы и сохранить - просто для получения идентификатора.

0 голосов
/ 08 февраля 2009

Я знаю ничего о NHibernate (OPF, который я использую, делает это для меня), но разве это не тот случай, когда при сохранении сводного корня (ShoppingCart) этот код также должен фиксировать свой составной собственник экземпляры для сеанса тоже?

0 голосов
/ 08 февраля 2009

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

...