Why does my class store one collection in the database and not another?

It drives me crazy. I can get one of the collections to save in the class, but not in the other.

I have a class called Category

 public Category() { Items = new List<Item>(); Prices = new List<Price>(); } 

These are two of these methods that are pretty much identical. Constructors define a property called Category , and their Name and Price respectively.

 public virtual Item AddItem(string name) { var item = new Item(this, name); Items.Add(item); return item; } public virtual Price AddPrice(decimal price) { var price = new Price(this, price); Prices.Add(price); return price; } 

Mappings

 public class CategoryMap : ClassMap<Category> { public CategoryMap() { // Other properties HasMany(x=>x.Items).Cascade.AllDeleteOrphan(); HasMany(x=>x.Prices).Cascade.AllDeleteOrphan(); } } 

As you can see, the two collections are displayed in exactly the same way.

Maps for Price and Item have the same display.

 References(x=>x.Category); 

As far as I can tell, almost all of the two are the same. Here is the problem

 category.AddItem(someName); session.Save(category); // Works category.AddPrice(somePrice); session.Save(category); // Doesn't work 

These are the files that I use to populate the test database. Saving an item works great. Saving prices - no. Classes and mappings are identical. I can not understand.

Mappings should work fine, as the constructor call directly works fine

 session.Save(new Price(category, 1)); 

So why does a category save one collection and not another? I ran the profiler and the class didn’t even try to save the price collection.

Update:

As Gabe notes in a comment, if I swap calls so that the price is called before the item, the price goes to the database, and the item does not.

If I call session.Flush() after each collection update, it works fine. Do I have to do this, or is there a way to fix my mapping so that it works?

+4
source share
1 answer

Try changing the order of the calls (first add the price, then the item) to see if this is really a problem with the Price display, or if the problem is that the second call fails.

Regarding flush - in most cases you do not need to explicitly call flush , this is what nHibernate will do in the background when necessary ( details here ). Flash mode is not a matching issue (this is a session property that you can set, but again usually you don’t need to).

If you assure your code in a transaction, flush not required. If you do not, you must be, and this may be your problem.

 using (var tx = Session.BeginTransaction()) { category.AddItem(someName); category.AddPrice(somePrice); session.Save(category); tx.Commit(); } 

update . I think I know what your problem was. Given your code, it looks like you are creating a new category object and populating it with data. In the first Save() nHibernate performs an automatic flash, because it cannot assign category_id to a child collection until it receives one from db. But the second time, category has an identifier, so the session does not need to be immediately cleared. nHibernate does not chat with the database when it is not needed. The solution, as I mentioned above, is to always use transactions to indicate when you did your work.

+1
source

Source: https://habr.com/ru/post/1399831/


All Articles