Using Criteria to get only base types - fluent-nhibernate

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

Related

How are to-many attributes specified in a fetched property?

I have two entities, Parent and Child. The Parent entity has a to-many relationship to Child named "children." Child has a String attribute named "childName."
I want to make a fetched property on Parent, let's call it "specialChild" that returns a Child with a particular name, let's say "Special". The following predicates return an empty set when I access the fetched property:
children.childName == "Special"
SUBQUERY(children, $eachChild, $eachChild.childName =
"Special").#count > 0
SUBQUERY(children, $eachChild, ANY $eachChild.childName =
"Special").#count > 0
I believe I'm messing up the predicate somehow, because I'm still pretty inexperienced with them. (and I can find zero documentation from Apple on "SUBQUERY") How am I supposed to specify "the child whose childName is Special" in the Parent's fetched property predicate?
Yes, I am calling -refreshObject:mergeChanges: but I still receive an empty result. Yes, the destination entity is Child.
What you want is parent==$FETCH_SOURCE AND childName=="Special". This gets any Child whose childName is "Special" and whose parent is the object looking up its special children.
Attributes in a fetched property predicate must exist on the destination entity. Here the destination is Child, so you can't use children since that only exists on Parent.
The $FETCH_SOURCE part corresponds to where you'd use self if you wrote the predicate in code. Without that you get every special child, not just the ones attached to the originating Parent. It says, the parent attribute of the child must be the specific instance looking up the fetched property value.

How do I add a CSLA Business Rule that depends on a property contained in the parent?

I am adding a "rounding" business rule to round a decimal property value to the number of decimal places specified in a separate integer property. This works nicely if both properties are members of the business object in question. As in the following VB.Net code...
BusinessRules.AddRule(New Round(_decimalProperty, _precisionProperty))
I have a private Round class that inherits from CommonBusinessRule and its constructor is as follows:
Public Sub New(decimalProperty As IPropertyInfo, precisionProperty As IPropertyInfo)
MyBase.New(decimalProperty)
InputProperties = New List(Of IPropertyInfo)()
InputProperites.Add(decimalProperty)
InputProperties.Add(precisionProperty)
End Sub
This triggers the rule Execute whenever either property changes, and the Execute code rounds just exactly like I want.
The Problem: I now have a situation where the precisionProperty is a property of the Parent business object. When the CSLA method for adding Business Rules for the Child Business Object is called, the Parent member of the Child Business Object is null, so I can't get to a reference of the parent's property. Is there any point in time AFTER the Parent field is no longer null, that I am allowed to add a new Business Rule? If so in what method? Is there another approach?
We have looked into passing down a reference to the parent business object (via constructors) to the child, but have decided against this approach for now (the child is actually 6 levels deep, and it appears this would require rework of our code generation schemes).
The parent property in the BusinessBase is generally used by the BusinessListBase to keep a relationship with its children. The parent property really isn't(shouldn't be?) used outside of that.
When I have a parent object with a property that affects child objects, I put the rule in the parent object that will then invoke any rules on the child object. You can pass in any values you like, even to the point of having a copy of the property on the child and just setting that as the parent property changes.

Get the ID of a child entity just after a parent has been saved

There is a parent entity that has a collection of child entities (cascale=all) and each child entity has a collection of grand-child entities (cascale=all).
Given a session, I create a grand-child and add it to the children of a child in the parent and since I also modified some other objects inside the hierarchy, I call Session.SaveOrUpdate on the root (parent).
After this I need the id of the grand-child entity but it is 0.
Now if I additionally call Session.SaveOrUpdate on the grand-child too, then I can get its new id. Is it normal behavior? With the cascades set to all, I would have thought that I could get the id when saving the parent.
Any enlightments?
SaveOrUpdate, when called on an already-persistent interface does nothing.
You can either call session.Persist(parent), which will cascade, or call session.Save(grandChild) as you're already doing (there's nothing wrong with this, although I wonder what you need that Id for)

NHibernate Component mapping (Creating Criteria)

Is there any way to create an “alias” for a component?
I have a “Criteria Builder” that takes strings in the format of “Address.City” (or “User.Address.City”, …) and creates an ICriteria (filters and sorts) based on it.
I am using components to map the “Address” class so it stays in the same table as “User”.
The exception I am getting is:
NHibernate.QueryExceptioncould not resolve property: City of: MyNamespace.User
If I attempt to do not create an “alias” for the Address Component, it works just fine.
However, as it is a criteria builder, is there a way to detect that “Address” is a component and avoid the call criteria.CreateAlias(“Address”)? Any work around?
This is the same question as mine, however the solution is not viable to me (I do not create criteria manually for each query).
Any help would be much appreciated!
You can't create an Alias for Address because Address is not a mapped entity. The only difference between CreateAlias and CreateCriteria is that the former returns the original Criteria, whereas the latter returns the new Subcriteria. So the only classes you can create Criteria for are classes that have been mapped. Since components are not mapped classes, you can't create a criteria around them.
The only suggestion I have is to have your Address class either to implement an empty descriptor interface like IComponent or mark it with a custom ComponentAttribute. Then your CriteriaBuilder can check whether or not the class it's creating a criteria for has this meta data and ignore it.

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