Bonjour,
pour un projet de programmation asp.net, j'ai décidé d'utiliser NHibernate pour me faciliter la vie.
Après 2jours de tests, d'essais et de debug, je commence à bien comprendre NHibernate.
Sauf que je me heurte maintenant à une magnifique NonUniqueObjectException
Après de nombreuses recherches, impossible de trouver une solution sur internet, donc peut être que l'un de vous pourra m'aider
J'ai une classe Product et une classe Shop
Elles sont assez simple car je suis en R&D donc pas besoin de trop me compliquer pour le moment
Product.cs
Product.hbm.xml
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Project.Entities { public class Product { public static string ID_DBNAME = "productid"; public virtual int id { get; protected set; } public virtual string name { get; set; } public virtual string category { get; set; } public virtual IList<Shop> most_selling { get; set; } public virtual IList<Shop> selling { get; set; } public Product() { most_selling = new List<Shop>(); selling = new List<Shop>(); } } }
Shop.cs
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="ClassLibrary1" namespace="Project.Entities"> <class name="Product" table="[Products]" dynamic-insert="true" dynamic-update="true" lazy="false"> <id name="id" type="int" unsaved-value="0"> <column name="productid" sql-type="int"/> <generator class="native"/> </id> <property name="name" type="string"> <column name="name" not-null="true" unique="false" sql-type="nvarchar(50)"/> </property> <property name="category" type="string"> <column name="category" not-null="true" unique="false" sql-type="nvarchar(50)"/> </property> <bag name="most_selling" lazy="false" cascade="all"> <key column="most_selled" /> <one-to-many class="Shop" /> </bag> <bag name="selling" table="[ShopProducts]" lazy="false" cascade="all"> <key column="productid"/> <many-to-many class="Shop" column="shopid"/> </bag> <!-- <joined-subclass name="FreeProduct" table="[FreeProducts]"> <key column="productid"/> <property name="toto" type="string"> <column name="toto" not-null="true" unique="false" sql-type="nvarchar(50)"/> </property> </joined-subclass> --> </class> </hibernate-mapping>
Shop.hbm.xml
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Project.Entities; namespace Project.Entities { public class Shop { public static string ID_DBNAME = "shopid"; public virtual int id { get; set; } public virtual string name { get; set; } public virtual Product most_selled { get; set; } public virtual IList<Product> catalog { get; set; } public Shop() { catalog = new List<Product>(); } } }
Je me suis fait une petite classe utile
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="ClassLibrary1" namespace="Project.Entities"> <class name="Shop" table="[Shops]" dynamic-insert="true" dynamic-update="true" lazy="false"> <id name="id" type="int" unsaved-value="0"> <column name="shopid" sql-type="int"/> <generator class="native"/> </id> <property name="name" type="string"> <column name="name" not-null="true" unique="false" sql-type="nvarchar(50)"/> </property> <many-to-one name="most_selled" class="Product" column="most_selled" lazy="false" cascade="all"/> <bag name="catalog" table="[ShopProducts]" lazy="false" cascade="all"> <key column="shopid"/> <many-to-many class="Product" column="productid"/> </bag> </class> </hibernate-mapping>
NHibernateHelper.cs
et des petits DAO
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 using System; using System.Collections.Generic; using System.Linq; using System.Text; using NHibernate; using NHibernate.Cfg; using NHibernate.Tool.hbm2ddl; using Project.Entities; namespace Project.Persistance { public class NHibernateHelper { protected static NHibernateHelper singleton = null; protected static ISessionFactory factory = null; protected static ISession session = null; protected NHibernateHelper() { Configuration configuration = new Configuration(); configuration.Configure(@"C:\users\admin\documents\visual studio 2010\Projects\WebApplication2\ClassLibrary1\Persistance\hibernate.cfg.xml"); configuration.AddXmlFile(@"C:\users\admin\documents\visual studio 2010\Projects\WebApplication2\ClassLibrary1\Mappings\Product.hbm.xml"); configuration.AddXmlFile(@"C:\users\admin\documents\visual studio 2010\Projects\WebApplication2\ClassLibrary1\Mappings\Shop.hbm.xml"); //configuration.AddAssembly(typeof(Product).Assembly); //var schema = new SchemaExport(configuration); //schema.SetOutputFile(@"C:\users\admin\documents\visual studio 2010\Projects\WebApplication2\ClassLibrary1\Persistance\hibernate.txt"); //schema.Create(true, true); factory = configuration.BuildSessionFactory(); } ~NHibernateHelper() { //session.Transaction.Commit(); //session.Close(); } public static NHibernateHelper getSingleton() { if (singleton == null) singleton = new NHibernateHelper(); return singleton; } public ISession openSession() { return factory.OpenSession(); } } }
ProductDAO.cs
ShopDAO.cs
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 using System; using System.Collections.Generic; using System.Linq; using System.Text; using NHibernate.Cfg; using Project.Entities; using NHibernate.Tool.hbm2ddl; using NHibernate; using NHibernate.Criterion; using Project.Persistance; namespace Project.DAO { public class ProductDAO { public ProductDAO() { } public Product getProductById(Int32 id) { Product ret; using (ISession session = NHibernateHelper.getSingleton().openSession()) { //using (ITransaction transaction = session.BeginTransaction()) //{ ret = session.CreateCriteria(typeof(Product)).Add(Restrictions.Eq(Product.ID_DBNAME, id)).UniqueResult<Product>(); //} session.Flush(); } return ret; } public List<Product> getAllProducts() { List<Product> ret; using (ISession session = NHibernateHelper.getSingleton().openSession()) { //using (ITransaction transaction = session.BeginTransaction()) //{ ret = session.CreateCriteria(typeof(Product)).List<Product>().ToList<Product>(); //} session.Flush(); } return ret; } public void saveProduct(Product product) { using (ISession session = NHibernateHelper.getSingleton().openSession()) { //using (ITransaction transaction = session.BeginTransaction()) //{ session.SaveOrUpdate(product); session.Flush(); // transaction.Commit(); //} } } public void saveProducts(List<Product> products) { using (ISession session = NHibernateHelper.getSingleton().openSession()) { //using (ITransaction transaction = session.BeginTransaction()) //{ foreach (Product product in products) { session.SaveOrUpdate(product); } session.Flush(); // transaction.Commit(); //} } } } }
Pour tester, j'ai rajouter un Object Product most_selled à la classe Shop
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Project.Entities; using NHibernate; using Project.Persistance; using NHibernate.Criterion; namespace Project.DAO { public class ShopDAO { public Shop getShopById(Int32 id) { Shop ret; using (ISession session = NHibernateHelper.getSingleton().openSession()) { //using (ITransaction transaction = session.BeginTransaction()) //{ ret = session.CreateCriteria(typeof(Product)).Add(Restrictions.Eq(Shop.ID_DBNAME, id)).UniqueResult<Shop>(); //} session.Flush(); } return ret; } public List<Shop> getAllShops() { List<Shop> ret; using (ISession session = NHibernateHelper.getSingleton().openSession()) { //using (ITransaction transaction = session.BeginTransaction()) //{ ret = session.CreateCriteria(typeof(Shop)).List<Shop>().ToList<Shop>(); //} session.Flush(); } return ret; } public void saveShop(Shop shop) { using (ISession session = NHibernateHelper.getSingleton().openSession()) { //using (ITransaction transaction = session.BeginTransaction()) //{ session.SaveOrUpdate(shop); session.Flush(); // transaction.Commit(); //} } } public void saveShops(List<Shop> shops) { using (ISession session = NHibernateHelper.getSingleton().openSession()) { //using (ITransaction transaction = session.BeginTransaction()) //{ foreach (Shop shop in shops) { session.SaveOrUpdate(shop); } session.Flush(); // transaction.Commit(); //} } } } }
Et dans la classe product j'arrive à récupérer une Collection de Shop où le produit est marqué comme most_selled
Maintenant mon problème vient du catalogue dans la classe Shop : une Collection de Product
Elle marche dans un sens mais quand je rajoute dans la classe Product une collection de Shop ou il apparait dans la catalogue ça plante quand je sauvegarde le Shop en bdd
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 namespace WebApplication2 { public partial class Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { ProductDAO productDAO = new ProductDAO(); ShopDAO shopDAO = new ShopDAO(); List<Product> plist = new List<Product>(); plist.Add(new Product() { name = "prod1", category = "cat1" }); plist.Add(new Product() { name = "prod2", category = "cat1" }); plist.Add(new Product() { name = "prod3", category = "cat1" }); plist.Add(new Product() { name = "prod4", category = "cat2" }); plist.Add(new Product() { name = "prod5", category = "cat3" }); plist.Add(new Product() { name = "prod6", category = "cat3" }); plist.Add(new Product() { name = "prod7", category = "cat4" }); plist.Add(new Product() { name = "prod8", category = "cat4" }); productDAO.saveProducts(plist); //plist = null; //GC.Collect(); List<Shop> pshop = new List<Shop>(); pshop.Add(new Shop() { name = "shop1", most_selled = productDAO.getAllProducts().ElementAt<Product>(0) }); pshop.Add(new Shop() { name = "shop2", most_selled = productDAO.getAllProducts().ElementAt<Product>(1) }); pshop.Add(new Shop() { name = "shop3", most_selled = productDAO.getAllProducts().ElementAt<Product>(2) }); shopDAO.saveShops(pshop); //pshop = null; //GC.Collect(); Shop shop_0 = shopDAO.getAllShops().ElementAt<Shop>(0); shop_0.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(0)); shop_0.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(1)); shop_0.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(2)); shop_0.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(3)); shopDAO.saveShop(shop_0); Shop shop_1 = shopDAO.getAllShops().ElementAt<Shop>(1); shop_1.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(4)); shop_1.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(5)); shop_1.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(6)); shop_1.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(7)); shop_1.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(0)); shopDAO.saveShop(shop_1); Shop shop_2 = shopDAO.getAllShops().ElementAt<Shop>(2); shop_2.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(3)); shop_2.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(4)); shop_2.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(2)); shop_2.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(3)); shop_2.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(4)); shop_2.catalog.Add(productDAO.getAllProducts().ElementAt<Product>(5)); shopDAO.saveShop(shop_2); foreach (Product product in productDAO.getAllProducts()) { panel.Controls.Add(new Label() { Text = "Product "+product.id+" "+product.name+" "+product.category+"<br />" }); foreach (Shop shop1 in product.most_selling) { panel.Controls.Add(new Label() { Text = " most selled in shop " + shop1.id + " " + shop1.name + "<br />" }); } foreach (Shop shop2 in product.selling) { panel.Controls.Add(new Label() { Text = " appears in catalog of shop " + shop2.id + " " + shop2.name + "<br />" }); } } panel.Controls.Add(new Label() { Text = "<br /><br /><br />" }); foreach (Shop shop in shopDAO.getAllShops()) { panel.Controls.Add(new Label() { Text = "Shop " + shop.id + " " + shop.name + "<br />" }); foreach (Product product1 in shop.catalog) { panel.Controls.Add(new Label() { Text = " sell product " + product1.id + " " + product1.name + " " + product1.category + "<br />" }); } } } } }
et voila l'exception :
quand j'enlève la collection de Shop dans la classe Product sa marche nikel,Server Error in '/' Application.
a different object with the same identifier value was already associated with the session: 1, of entity: Project.Entities.Product
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: NHibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 1, of entity: Project.Entities.Product
Source Error:
Line 46: //using (ITransaction transaction = session.BeginTransaction())
Line 47: //{
Line 48: session.SaveOrUpdate(shop);
Line 49: session.Flush();
Line 50: // transaction.Commit();
Source File: C:\Users\ADMIN\documents\visual studio 2010\Projects\WebApplication2\ClassLibrary1\DAO\ShopDAO.cs Line: 48
Stack Trace:
[NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 1, of entity: Project.Entities.Product]
NHibernate.Engine.StatefulPersistenceContext.CheckUniqueness(EntityKey key, Object obj) +176
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformUpdate(SaveOrUpdateEvent event, Object entity, IEntityPersister persister) +449
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsDetached(SaveOrUpdateEvent event) +350
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event) +165
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event) +327
NHibernate.Impl.SessionImpl.FireSaveOrUpdate(SaveOrUpdateEvent event) +199
NHibernate.Impl.SessionImpl.SaveOrUpdate(String entityName, Object obj) +159
NHibernate.Engine.SaveUpdateCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled) +98
NHibernate.Engine.Cascade.CascadeToOne(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) +186
NHibernate.Engine.Cascade.CascadeAssociation(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) +87
NHibernate.Engine.Cascade.CascadeProperty(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) +121
NHibernate.Engine.Cascade.CascadeCollectionElements(Object child, CollectionType collectionType, CascadeStyle style, IType elemType, Object anything, Boolean isCascadeDeleteEnabled) +666
NHibernate.Engine.Cascade.CascadeCollection(Object child, CascadeStyle style, Object anything, CollectionType type) +265
NHibernate.Engine.Cascade.CascadeAssociation(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) +171
NHibernate.Engine.Cascade.CascadeProperty(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled) +121
NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything) +540
NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent) +41
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.CascadeOnUpdate(SaveOrUpdateEvent event, IEntityPersister persister, Object entity) +142
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformUpdate(SaveOrUpdateEvent event, Object entity, IEntityPersister persister) +888
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsDetached(SaveOrUpdateEvent event) +350
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event) +165
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event) +327
NHibernate.Impl.SessionImpl.FireSaveOrUpdate(SaveOrUpdateEvent event) +199
NHibernate.Impl.SessionImpl.SaveOrUpdate(Object obj) +160
Project.DAO.ShopDAO.saveShop(Shop shop) in C:\Users\ADMIN\documents\visual studio 2010\Projects\WebApplication2\ClassLibrary1\DAO\ShopDAO.cs:48
WebApplication2.Default.Page_Load(Object sender, EventArgs e) in C:\Users\ADMIN\documents\visual studio 2010\Projects\WebApplication2\WebApplication2\Default.aspx.cs:47
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
System.Web.UI.Control.OnLoad(EventArgs e) +91
System.Web.UI.Control.LoadRecursive() +61
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1966
mais j'aimerai vraiment à faire marcher le double sens
Pour la bdd, le hbm me génère automatiquement les tables
avec des clés étrangères
et une table qui correspond au many-to-many entre Product et Shop
Une petite idée de comment régler l'exception ?
Merci beaucoup !
Partager