Custom entity creation (construction) in NHibernate - nhibernate

I have Order class and SubOrder: Order descendant. Now, Order has .Item and SubOrder (obviously) has it, too, but SubOrder needs SubItem to be there. Which is easy when created:
Item = new SubItem((ISomeInterface)this);
but how do I tell NHibernate to create SubItem instead of Item when it loads SubOrder from database (Session.Get<SubOrder>(id))? The type of the item is not in the database (and I don't need and don't want it to be there); it's always "Item for Order, SubItem for SubOrder". Moreover, it needs to be created with (ISomeInterface)SubOrder as constructor parameter.
In short, how do I manage custom entity create in NHibernate to achieve things described above? Is it possible to have a reference to SubOrder when creating SubItem (I can live with property "injection" if not)?
I can probably use IUserType but it seems to be an overkill; and I don't see how to apply IUserType to SubOrder.Item only (same for IInterceptor). Also I don't see how to get a reference to the parent order, except to use OnLoad event for the SubOrder and set SubItem properties there... which is awkward.

"OnLoad event for the SubOrder and set SubItem properties there" -> there's one solution.
Otherwise you could try writing a custom ReflectionOptimizer.

Related

Making decisions on designing classes interfaces

I would like to get some thoughts from others about the following problem.
Let's assume we have two classes Products and Items. Products object allows us to access any Item object. Here's the example.
$products = new Products();
// get existing item from products
$item = $products->get(123);
// create item
$item = $products->create();
$item->setName("Some new product");
$item->setPrice(2.50);
Now what would be the best way to update/save state of the item? I see 2 options:
$item->save();
or
$products->save($item);
First aproach seems very straigh forward. Once attributes of Item object are set calling save method on it will persist changes.
On the other hand I feel like latter approach is better. We're separating the roles of two objects. Item object contains only state and Products object operates on that state. This solution may be also better for writing unit tests.
Any thoughts?
So, effectively the items are buffering the actual changes.
Clearly both approaches will work, however it comes down to how closely you want to adhere to the underlying database's model or the overlaid object model.
Viewed from the outside, $item->save() makes the most sense in terms of the model - as you point out, you update the item's properties and then save them down. Plus it is conceptually an action that is performed on the item.
However, $products->save($item) offers two noticable advantages, and a drawback.
On the plus side, by moving save into products, it can (potentially) handle batching / reordering of the updates in a smarter way since it has visibility of all the items. It also allows the save code to be used as ->add() (more or less)
A downside is it is going to (from the object model view) add the following possible use, which you probably don't want:
$p1 = new Products();
$p2 = new Products();
$item = $p1->create();
// set $item values
$p2->save($item);
Obviously, you could just add an 'is this mine? no? then throw an error' test to Products::save, but that is extra code for blocking a use case the syntax implies could/should work. Or at least would probably slip through a code review.
So, I'd say go with the approach that seems the simplest and binds tightest to the desired functionality ($item->save()), unless you need to do caching/batching/whatever that forces you to go with the other.

Binding an NSPopupButton to an NSArrayContraller with NSManagedObject subclasses

There seem to be dozens of questions about binding a NSPopupButton, so I feel a little better about struggling so much with this, but none of them seem to fix my issue.
I have an NSManagedObject subclass that has a one to many relationship with another class. Let's say Foo has a relationship to Bar, so Foo has a property that is an NSSet of Bars.
I have created an NSArrayController and bound its contentSet to the Foo object and the 'bars' key path.
I then bind my NSPopupButton's content to the array controller's arrangedObjects and its contentValues to the array controller's arrangedObject (controller key) and 'name' (the property on Bar that I want to display).
This all works fine so far, but when I try to bind the NSPopupButton's selected object to the array controller's selection The NSPopupButton displays "<_NSArrayControllerObjectProxy". I also tried adding 'name' as the keyPath for this binding, and this does make the NSPopupButton display the name correctly, but then when I change the selection in the popup the app thrown an exception:
Unacceptable type of value for attribute: property = "name"; desired type = NSString; given type = Bar;
I guess this makes sense, as the popup is trying to set the string value of 'name' as the selected Bar. I would think I would therefore need to bind a selected object and a selected value, but the XIB will disable selected value if I have a selected object set.
I have also tried binding the selected value instead, and this half works (the array controller's selection does change) but the options in the popupmenu don't change to show the one that was deselected and hide the newly selected one).
Failing all of this I read an article here: http://blog.chrisblunt.com/cocoa-bindings-and-nspopupbutton/ that says NSPopupButton "NSPopUpButton does not record the user’s selection" and to instead store your selection somewhere other than the array controller. I tried putting a currentBar property in my window and binding the selection to that instead, and although I can see that currentBar is changing (because I have another view bound to it also) the label in the popup button does not change.
If anyone can help me out I'd be very appreciative.
The FooBar thing confuses me so here is my example based on real world objects.
ExpenseTransaction has attributes (date, trxDescription, category, amount).
Category has a single attribute (name)
ExpenseTransaction.category is a To-One relationship to Category (in other words a transaction can belong to only one Category).
Category.transactions is a To-Many relationship to ExpenseTransaction (in other words many transactions can belong to the same Category).
The UI for creating a new transaction or editing and existing one uses NSPopupButton to display the list of available Categories using the name attribute. For existing transactions the popup will display the selected transactions category.
Bindings for the Category popup are as follows:
Content (Category.arrangedObjects)
Content Objects (Category.arrangedObjects) - we want to link to the actual category not its name because the attribute is a relationship not a string value
Content Values (Category.arrangedObjects.name) - we want the name to be displayed in the popup list
Selected Object (ExpenseTransaction.selection.category)
Using your FooBar analogy:
Category has a relationship to ExpenseTransaction, so Category has a property (transactions) that is a NSSet of ExpenseTransactions. Now this is pretty much the inverse of my arrangement so I don't really know how or why you would populate the popup with ExpenseTransaction objects because only one selected item in the popup could be related to the Category object when in fact you need the whole set to be related. However the other way around works just fine because the popup would contain a list of all the Foo items and so whenever you select a Bar item the corresponding Foo item could be selected from the popup.
Hope this makes sense.

How to add new values to nested Core Data objects?

My Core Data object model has three nested objects as shown below:
Item
Beverage
Brand
When I first create an instance of Item
Item *item = [NSEntityDescription insertNewObjectForEntityForName:#"Item" inManagedObjectContext:self.objectContext];
the item.beverage property is nil. Next I want to store a value in the item.beverage.brand.title property.
Do I have to create an instance of Beverage and assign it to item.beverage, then create an instance of Brand and assign it to item.beverage.brand.
item.beverage = [NSEntityDescription insertNewObjectForEntityForName:#"Beverage" inManagedObjectContext:self.objectContext];
item.beverage.brand = [NSEntityDescription insertNewObjectForEntityForName:#"Brand" inManagedObjectContext:self.objectContext];
before I can finally assign the value to the title property?
item.beverage.brand.title=#"Sample Title";
Is there a shorter/less verbose way to do this?
You need to create each object in the object graph. I'm not aware of any core-data provided shortcuts. You could of course write your own methods, categories, or macros to reduce the verbosity if you find your self writing a lot of boiler plate code.
If the purpose of your separate entities is primarily encapsulation of behavior or normalization of data, it sometimes occurs that you never wish to insert a parent without automatically inserting a child. In your case, this could be an Item that always, without fail, has a Beverage.
In this case, you could set the relationship between Item and Beverage to be non-optional and to-one, with a cascading delete rule. Together, these reflect the fact that the one is meaningless without the other. Unfortunately, in that case, insertion of the Item still does not insert the Beverage. To do that, override awakeFromInsert to perform this insertion and then it will be automatically present whenever an instance of Item is created.
If on the other hand it is possible that an Item may not have a Beverage, but that when it does, that Beverage always has a name, as the other poster commented, it's also a possibility that adding custom logic - Item.setBrandname, which inserts a Beverage if it is not already present - is a viable solution.
Your business logic drives this kind of decision.
Also, fwiw, 'item', while not a reserved keyword, may be a good word to avoid as a class/variable name because it's an abstract/programming-related concept. That's entirely separate from the rest of my answer. ;-)

Return only the Parent using nHibernate

Im pretty new to nhibernate so this may be quite straightforward but i havent found an answer on the web yet.
Lets say i have a Parent class and a Child class. The Parent Class can have many Child classes associated with it. Now when i try to load a specific Parent nhibernate also populates its Child collection for me. There are situations where I want to just return a Parent class without a Child collection.
I know i can turn on Lazy loading but that wont work as im serializing the Parent to XML. The XML serialiser cannot work with the nhibernate PersistanceBag that contains the Child collection.
So is there a way to define a Parent class, lets say ParentView which works on the same table but only contains the Parent properties and not all its children and grandchildren?
Define a class ParentView that contains the columns you need to retrieve. Make sure this class has one parameterless constructor.
ISession session = NHibernateHelper.Session;
ISQLQuery query = session.CreateSQLQuery("select Parent_ID, Name form Parent where Parent_ID = :parentID");
query.SetInt32("parentID", parentID);
IList<ParentView> parentView = query.SetResultTransformer(Transformers.AliasToBean<ParentView>()).List<ParentView>();
return parentView;
An alternative to creating a view class and associated query as suggested by sh_kamalh (which I would consider if I were you). If the problem is related to the bag mapping structure specifically then you might have a couple of easier solutions:
Option 1
Revisit the bag mapping - Maybe simple selecting a different strategy will fix the issue. I have answered a question on the different collection mappings before List vs Set vs Bag in NHibernate personally I find that I use the Set strategy a lot. To map a different strategy in Fluent NHibernate use the following as a guide in your override.
mapping.HasMany<Child>(x => x.Children).ToSet();
or
mapping.HasMany<Child>(x => x.Children).ToList();
Option 2
Not particularly related to NHibernate but if you are using the default xml serializer you might be able to tell the xml serializer to simply ignore that property and leave the bag mapping in place.
[System.Xml.Serialization.XmlIgnore]
public IEnumerable<Child> Children { get; internal set; }

Using Criteria to get only base types

I'm looking for way in Fluent NHibernate to get a list of all object of type PARENT
using criteria.
I have a father object and a derived child.
The father contains a list of childs.
The problem is that when I use:
ICriteria crit = session.CreateCriteria(typeof(Parent))
IList<Parent> myRes = crit.List<Parnet>()
NH return back the list of both parent elements and the derived children elements, which is "right" b/c that is what I've asked, but that is not what I need.
(the children elements should be only inside the father object, but since they are of type parent as well - since they derived from it... NH brings them as well using this method.)
How can I get the list of all my "father" elements without the derived children ?
This is from the first answer (#Stefan Steinegger's)
session
.CreateQuery("from Parent where Parent.class == :class")
.AddType(typeof(Parent));
It looks like I need something like that - but it doesn't work in Fluent NHibernate.
Thanks,
Dani
the question actually is: how do you determine if a Parent is a root parent? there are various approaches:
You keep your model and define: a root is a Parent that is not inherited and is not included in any other Parent.
The part "is not inherited" might be easy to determine, but is actually a poor definition. When using inheritance, you should actually not care if an object you get as a certain type is actually inherited or not, this is the nature of inheritance.
The part "is not included in any other Parent" is hard to find out in an efficient way.
You set a reference to an objects parent. A root is a Parent where its parent references null.
You derive your Root from a common Base class. A Child is not a Root anymore, and a Root is a Root.
I suggest to take the last option.
BTW: you can filter for the exact type, but only using HQL.
session
.CreateQuery("from Parent where Parent.class == :class")
.AddType(typeof(Parent));