NHibernate: Using Fluent Nhibernate to save child objects

末鹿安然 提交于 2019-12-03 06:38:40

问题


In my system, I have two entities - ShoppingCart and ShoppingCartItem. Fairly generic use-case. However, when I save my ShoppingCart, none of the items are being saved to the DB.

Within my object, I create a new ShoppingCart object.

ShoppingCart cart = CreateOrGetCart();

I then add an existing Product which I got from the database to the start.

cart.AddItem(product);

This is just a simple wrapper to add the item to the IList.

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

I then call SaveOrUpdate on the Repository

Repository.SaveOrUpdate(cart);

Which looks like this:

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

I'm using Fluent NHibernate for the mapping:

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

Database Schema (SQL Server 2005) is also fairly generic:

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

When I SaveOrUpdate my ShoppingCart, why isn't any ShoppingCartItems also being saved?

Please help.

Thanks

Ben

UPDATE: Wrapping it in a transaction providng me with some more info:

Cannot insert the value NULL into column 'ShoppingCartId', table 'WroxPizza.dbo.ShoppingCartItems'; column does not allow nulls. INSERT fails. The statement has been terminated.

This is because it's a new cart.


回答1:


I had this exact problem with fluent nhibernate. There appears to be a small bug in mapping one-to-many relationships and the relationships not automatically saving or cascading. See here for a posting about it on the Fluent NHibernate group.

Apparently, there is someone working on the issue!

I can;t say for sure that this is the issue with your code but it looks very similar to a problem I had. Hope that helps some!




回答2:


Why did you include .Cascade.SaveUpdate() in the line

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

?

Perhaps it confuses NHibernate (or Fluent NHibernate) that there seems to be cascading saves/updates from both ends of your relation?

Configuring your HasMany to cascade ought to be sufficient to achieve what you want.




回答3:


Try wrapping Session.SaveOrUpdate in a transaction, or force a flush directly after.




回答4:


I'm not sure, but I don't think that NHibernate cascades the saving of objects to child objects. You don't show the code that calls SaveOrUpdate, but I know if you loop through the ShoppingCartItems at that point, saving each individually then they'll be persisted too.




回答5:


I know nothing about NHibernate (The OPF I use does this for me), but isn't it the case that when you save the aggregate root (ShoppingCart) that code should also commit its compositely owned instances to the session too?




回答6:


Is it possible that your cart items are saving first, then the cart? hence the child items have no parent ID to use?

You MAY need to explicitly save the cart back to the DB on create, then add the items into it and save - just to get the ID.




回答7:


As noticed, you defined (in the database schema) fields with Identity, therefore, these fields must be set in the Map file. Example as the following:

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

the error you are getting because you didn't set the Identity fields in the mapping to be generated by Identity, thus, when you are trying to Save(), the Identity column is not generated(and set to not null in the database) then it gives you the error.




回答8:


The problem is with your configuration statement of sessionfactory. Don't use Exposeconfiguration if u want your data to persist. That will surely solve your problem of data persistence.



来源:https://stackoverflow.com/questions/524974/nhibernate-using-fluent-nhibernate-to-save-child-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!