setfirstresult & setmaxresult in child collection - nhibernate

I have and entity lets call it Entity, and a Child collection Children.
I have a screen where the user has the Entity information, and a list with the Children collection, but that collection can be get very big, so i was thinking about using paging: get the first 20 elements, and lazy load the next only if the user explicitly presses the next button.
So i created in the Entity Repository a function with this signature:
IEnumerable<Child> GetChildren(Entity entity, int actualPage, int numberOfRecordsPerPage)
I need to use the setfirstresult and setmaxresult, not in the Agregate root Entity, but in the child collection. But when i use those two configurations, they allways refer to the entity type of the HQL/Criteria query.
Other alternative would be to create a HQL/Criteria query for the Child type, set the max and first result, then filter the ones who are in the Entity Children collection (by using subquery).
But i wasn't able to do this filter. If it was a bidirectional association (Child refering the parent Entity) it would be easier.
Any suggestions?
Any

One approach would be to create a query that returns results from both tables by doing a group by. This approach would allow you to apply paging on data that will come from the children collection and have a common factor (the entity's ID in each row) while you keep your starting point (the Entity object). What I mean is something like that:
public IList<object> GetData(int entityID, int actualPage, int numberOfRecordsPerPage)
{
ICriteria criteria = _repository.Session.CreateCriteria<FlowWhatIfProfile>("entity")
.CreateCriteria("Children", "children", NHibernate.SqlCommand.JoinType.InnerJoin)
.Add(Restrictions.Eq("children.EntityID", entityID));
ProjectionList pl = Projections.ProjectionList();
pl.Add(Projections.GroupProperty("children.Id"));
pl.Add(Projections.GroupProperty("children.Property1"));
pl.Add(Projections.GroupProperty("children.Property2"));
pl.Add(Projections.GroupProperty("children.Property2"));
pl.Add(Projections.GroupProperty("entity.Id"));
return criteria.SetProjection(pl)
.SetFirstResult(actualPage * numberOfRecordsPerPage)
.SetFetchSize(numberOfRecordsPerPage)
.List<object>();
}
The drawback would be that your returned data are a list of arrays (you will have to cast object to object[]) but you can overcome that by using the AliasToBean functionality that lest NHibernate project these arrays to strongly typed objects that you define.

it's simple with CreateFilter
session.CreateFilter(entity.children, "")
.SetFirstResult(0)
.SetMaxResults(20)
.List();
http://knol.google.com/k/fabio-maulo/nhibernate-chapter-16/1nr4enxv3dpeq/19#

Related

How to update two columns with same name from two tables in a join query

I am getting an error:
Property or Indexer cannot be assigned to "--" it is read only
when trying to update two columns with the same name in two tables in a join query. How do I get this to work? Thanks!
The anonymous object created in your projection ("select new" part) is read-only and its properties are not tracked by data context by any means.
Instead, you can try this:
//...
select new
{
p1 = p,
p2 = t
}
foreach (var row in updates)
{
row.p1.Processed = true;
row.p2.Processed = true;
}
In order to improve performance you may also want to take a look at batch update capabilities of Entity Framework Extensions (if you are using Entity Framework): https://entityframework-extensions.net/overview
Yes, that's due to anonymous type properties are read only, from documentation:
Anonymous types provide a convenient way to encapsulate a set of
read-only properties into a single object without having to explicitly
define a type first.
I suggest you to create a custom class with the two entities you need (a DTO):
public class PassengerDTO
{
public Passenger Passenger {get;set}
public PassengerItinerary PassengerItinerary {get;set}
}
And use it in your projection, You need the entity instances and not just the properties you want to modify because, when you modify the Processed property in the foreach the proxy class that represent your entity is going to change the status of you entity to Updated.

How to do a full text search with Nhibernate and get result ranks?

I have a SQL 2008 R2 database with full text indexing set up and would like to use NHibernate to get back search results with ranking. I've figured out the SQL queries usng FULLTEXTTABLE to get result rankings, but I'm struggling with how to use NHibernate to get results with the ranking value since it doesn't map to an actual column in any table.
Any pointers?
(First of all the following syntax will be a bit hazy because this is from memory, please check the api)
well you can either construct some DTO class and map that on-the-fly
for example:
public class Person
{
public virtual String Name {get;set;}
public virtual String Surname {get;set;}
}
which is properly mapped to nhibernate
and the
PersonDTO : Person
{
public int FTSRanking {get;set;}
}
which is not mapped. Note that i'm inheriting from class Person although that is not necessary and i'm only doing it for ease.
This PersonDTO class is only used on queries but there are limitations, as the following hql shows.
NHSes.CreateQuery('select p.Name, p.Surname, p.FTSAlias as FTSRanking from Person p')
.SetResultTransformer(Transformers.AliasToBean<PersonDTO>())
will return a PersonDTO which nhibernate manages to assemble because every item in the select list matches a property (in name, casing, type) in the PersonDTO class. Also you will have to manually type the select list and also, since it is not a mapped class, nhibernate cannot assemble collections.
An other option would be to use the Criteria API in which you set projections (aka extend the select list)
IList<object[]> results = NHSes.CreateCriteria(typeof(Person))
.Add(Expression.SQL(" your fts clause here "))
.SetProjection(Projections.SQL(" add your fts ranking column here",,), Projections.( here add as a projection the main entity ))
.List<object[]>();
where in the results variable each returned row is an object[] and the first element (ie results[0][0]) is the ranking and the second element (ie results[0][1]) is a properly managed Person object

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

Restricting an NHibernate query using ICriteria according to an enumeration of enums

I have an entity, with a field of type enum, that is persisted as an integer in my database.
When retrieving objects from the database using ICriteria, I wish to restrict the results to those with the field being a member of a collection of enum values. Does Restrictions.In work with a collection of enums?
The following does not work. Do I have to perform something like type-casting at the "restrictions.in" part of the query?
var myEnumCollection = new MyEnum[] { MyEnum.One };
return FindAll<MyType>(Restrictions.In("EnumProperty", myEnumCollection));
FindAll is a method encapsulating
criteria.GetExecutableCriteria(Session).List<MyType>()
My initial guess would be that you'll need to compare against the integer values of the enum members (assuming that you're mapping the enum as an integer); so something like:
var myEnumCollection = new int[] { MyEnum.One };
return FindAll<MyType>(Restrictions.In("EnumProperty", myEnumCollection));
May be the solution that you're after. If you update your post with further details (mapping of the enum member and the sql being generated by the query), I may be able to provide further assistance.

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