NHibernate: использование Fluent Nhibernate для сохранения дочерних объектов
В моей системе у меня есть два объекта - 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
Когда я SaveOrUpdate моей ShoppingCart, почему не сохраняются какие-либо ShoppingCartItems?
Пожалуйста, помогите.
Спасибо
Бен
UPDATE:
Обертывая его в транзакции, предоставляя мне дополнительную информацию:
Невозможно вставить значение NULL в столбец "ShoppingCartId", таблицу 'WroxPizza.dbo.ShoppingCartItems'; столбец не допускает нулей. INSERT терпит неудачу. Заявление завершено.
Это потому, что это новая тележка.
Ответы
Ответ 1
У меня была эта точная проблема с беглостью nhibernate. Кажется, существует небольшая ошибка при сопоставлении отношений "один ко многим", а отношения не сохраняются автоматически или каскадируются. См. здесь публикацию об этом в группе Fluent NHibernate.
По-видимому, кто-то работает над проблемой!
Я не могу сказать, что это проблема с вашим кодом, но он очень похож на проблему, которую я имел. Надеюсь, что это поможет!
Ответ 2
Почему вы включили .Cascade.SaveUpdate()
в строку
References(x => x.Cart, "ShoppingCartId").Cascade.SaveUpdate()
?
Возможно, это смущает NHibernate (или Fluent NHibernate), что, кажется, каскадные сбережения/обновления с обоих концов вашего отношения?
Настройка вашего HasMany в каскад должна быть достаточной для достижения желаемого.
Ответ 3
Попробуйте обернуть Session.SaveOrUpdate в транзакции или принудительно выполнить сброс сразу после.
Ответ 4
Я не уверен, но я не думаю, что NHibernate каскадирует сохранение объектов дочерним объектам. Вы не показываете код, который вызывает SaveOrUpdate, но я знаю, что если вы зацикливаете объекты ShoppingCartItems в этот момент, сохраняя их индивидуально, они также будут сохранены.
Ответ 5
Я знаю ничего о NHibernate (OPF, который я использую для этого, для меня), но не так ли, когда вы сохраняете корень агрегата (ShoppingCart), этот код должен также совершать его и на сессию тоже?
Ответ 6
Возможно ли, что ваши товары корзины сначала сохраняются, а затем тележка? поэтому дочерние элементы не имеют родительского идентификатора для использования?
Вам необходимо явно сохранить корзину обратно в БД при создании, затем добавить элементы в нее и сохранить - только для получения идентификатора.
Ответ 7
Как уже отмечалось, вы определили поля (в схеме базы данных) с идентификатором, поэтому эти поля должны быть установлены в файле карты. Пример:
Id(x => x.ID, "ShoppingCartItemId").GeneratedBy.Identity();
ошибка, которую вы получаете, потому что вы не задали поля Identity в сопоставлении, которые должны быть сгенерированы с помощью Identity, поэтому при попытке Save() столбец Identity не генерируется (и устанавливается не null в база данных), то она дает вам ошибку.
Ответ 8
Проблема заключается в вашей инструкции конфигурации sessionfactory. Не используйте Exposeconfiguration, если вы хотите, чтобы ваши данные сохранялись. Это наверняка решит вашу проблему сохранения данных.