NHibernate: à l'Aide de Fluent Nhibernate pour enregistrer les objets enfants
Dans mon système, j'ai deux entités - ShoppingCart et ShoppingCartItem. Relativement générique de cas d'utilisation. Cependant, lorsque je sauvegarde mon ShoppingCart, aucun des articles sont enregistrées dans la bd.
Au sein de mon objet, je crée un nouveau ShoppingCart objet.
ShoppingCart cart = CreateOrGetCart();
Je puis ajouter un Produit existant que j'ai obtenu à partir de la base de données pour le début.
cart.AddItem(product);
C'est juste un simple wrapper pour ajouter l'élément à la IList.
public virtual void AddItem(Product product)
{
Items.Add(new ShoppingCartItem { Quantity = 1, Product = product });
}
Je puis appeler SaveOrUpdate sur le Référentiel
Repository.SaveOrUpdate(cart);
Qui ressemble à ceci:
public T SaveOrUpdate(T entity)
{
Session.SaveOrUpdate(entity);
return entity;
}
J'utilise Couramment NHibernate pour la cartographie:
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();
}
Schéma de base de données (SQL Server 2005) est également assez générique:
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
Quand je SaveOrUpdate mon ShoppingCart, pourquoi n'est-il pas tout ShoppingCartItems également être sauvé?
S'il vous plaît aider.
Grâce
Ben
Mise à JOUR:
En l'enveloppant dans une transaction providng moi avec un peu plus d'info:
Impossible d'insérer la valeur NULL dans la colonne 'ShoppingCartId", table
'WroxPizza.dbo.ShoppingCartItems'; la colonne n'autorise pas les valeurs null.
INSERTION échoue. La déclaration a été résilié.
C'est parce que c'est un nouveau panier.
- James Grégoire solution a fonctionné pour moi.
Vous devez vous connecter pour publier un commentaire.
J'ai eu exactement ce problème avec nhibernate fluent. Il semble y avoir un petit bug dans la correspondance un-à-plusieurs liens et les relations qui ne sont pas automatiquement la sauvegarde ou en cascade. Voir ici pour une publication à ce sujet sur la fluidité de la NHibernate groupe.
Apparemment, il y a quelqu'un qui travaille sur la question!
Je peux pas dire pour sûr que c'est de la question avec votre code, mais il ressemble beaucoup à un problème que j'ai eu. L'espoir, qui permet à certains!
Pourquoi avez-vous d'inclure
.Cascade.SaveUpdate()
dans la ligne?
Peut-être qu'il confond NHibernate (ou NHibernate Fluent) qu'il semble y avoir une cascade de sauve/mises à jour à partir des deux extrémités de votre relation?
La configuration de votre HasMany en cascade doit être suffisant pour obtenir ce que vous voulez.
Essayer d'emballage Session.SaveOrUpdate dans une transaction, ou de force une chasse d'eau directement après.
Je ne suis pas sûr, mais je ne pense pas que NHibernate cascades de l'enregistrement des objets aux objets enfants. Vous n'avez pas montrer le code qui appelle SaveOrUpdate, mais je sais que si vous parcourez le ShoppingCartItems à ce point, l'enregistrement de chaque individuellement puis ils vont être conservées trop.
Je sais rien sur NHibernate (L'OPF-je utiliser cela pour moi), mais n'est-ce pas le cas que lorsque vous enregistrez la racine d'agrégat (ShoppingCart) que le code doit également s'engager sa compositely appartenant à des instances de la session de trop?
Est-il possible que votre panier les articles sont la sauvegarde de la première, ensuite le panier? donc, les articles n'ont pas de parent de l'ID à utiliser?
Vous devrez PEUT-être enregistrer explicitement le chariot vers la DB sur créer, puis d'ajouter les éléments dans il et enregistrez - juste pour obtenir l'ID.
Comme l'a remarqué, vous avez défini (dans le schéma de base de données) dans les domaines de l'Identité, par conséquent, ces champs doivent être définis dans le fichier de Carte. Exemple comme le suivant:
Id(x => x.ID, "ShoppingCartItemId").GeneratedBy.Identity();
l'erreur que vous obtenez parce que vous n'avez pas de définir l'Identité des champs dans la cartographie d'être générés par l'Identité, ainsi, lorsque vous essayez d'Enregistrer(), la colonne d'Identité n'est pas généré(et mise à not null dans la base de données), puis il vous donne le message d'erreur.
Le problème est avec votre configuration de l'état de la sessionfactory. N'utilisez pas de Exposeconfiguration si tu veux vos données à persister. Qui va certainement résoudre votre problème de la persistance des données.