I’m happy to announce that the next installment in the Summer of NHibernate screencast series is now available for general download from the main Summer of NHibernate site. This session was actually recorded in the middle of a raging thunderstorm that passed thru New York City so if you listen closely to the audio you can perhaps pick out the booming of thunder at certain points in the recording; hopefully its not too distracting .
That same storm actually temporarily knocked power out in my house for about 15-20 seconds and I was only able to keep recording thanks to the battery in my laptop — I guess there’s a good argument for not trying to record these on my desktop PC . If you watch closely, about 42 minutes into the screencast I loose my Ethernet connection and the network icon in the system tray pops up to tell me — that’s my 100-mip switch going dark for about 30 secs before power came back up properly. It wasn’t annoying enough to actually re-record that section so I just left it as-is.
Anyway, in this session we spend some up-front time evolving the way our NHibernateDataProvider class handles NHibernate session management to allow it to properly support our needs to do lazy-loading, separate the concern of creating sessions themselves out into a new NHibernateSessionManager class, and push the responsibility for creating sessions up into our test methods themselves so that they can properly manage session life-span at that level.
After we take care of those housekeeping chores, we move on to demonstrate querying across child collections in 1:many relations using both HQL and the Criteria API and then also spend some time digging into understanding the different ways that both query platforms support returning distinct objects from queries.
As always, comments, feedback, input, suggestions, and general criticism are appreciated from all.
Thanks for this great screencast. I have a question about “CodeRush”. When you (and I) do “t space” to create a “[Test] method” the namespace “NUnit.Framework” is added all the time …. but I use MbUnit and “MbUnit.Framework” is already added.
I have to begin a new project based with NHibernate, your screencasts are a providence :). Could you tell us based on your experience how organize the projects in the solution, which project do what, the naming convention you use, best practice …. You can use “old” method for that, write some sentences ๐
@Gabriel:
It turns out that if you look closely @ the screencasts in this series, this ISN’T what happens when I invoke the’t’ template expansion in my own copy of CodeRush — instead I get the MbUnit namespace(s) added to my test fixture source file(s).
I have (long ago) modified the ‘default’ CodeRush templates for the macro-expansion that creates tests, testfixtures, test-fixture-setups/teardowns, etc. to add the MbUnit.Framework namespace instead of the NUnit.Framework that is the default berhavior in CodeRush.
It won’t surprise you a bit to discover that I long-ago recorded a screencast on how to make these changes to your own CodeRush templates ๐
In case you’re interested, I have gone ahead and posted it for download (its only about 15 mins in length and 20MB in size) at the following URL:
http://www.summerofnhibernate.com/screencasts/CodeRushUnitTestTemplateChanges-video.zip
If you follow the process outlines in this video, you will ‘properly’ get ‘using MbUnit.Framework’ added to your files if its not already there and you won’t get ‘using NUnit.Framework’ at all anymore.
Happy Coding~!
@Gabriel:
I’m not sure if its possible for me to provide best-practices guidance for the organization of your project without knowing more about the specifics (e.g., even whether its a webforms, winforms, ASPNET MVC, services-only, etc. focused app) but I will use your request here as the basis for a post or two in the near-term, how’s that?
I’d like focus on Winforms and WebForms, not (yet) MVC, … In the video you use “DataTransfer” project, you put mapping file in the same directory class, it’s not “better” to put in a “mapping” folder. In the “DataAccessLayer” project, all is in the same .cs file (NHibernateDataPRovider). I’d like to know the best way to give name, organization folder in each project, ….
Hi Steve,
Great web-case once again.
I have a query which is not necessarily linked to the current web-cast but a general feature which I am looking for.
Can nHibernate map a stored procedures result set to a class? The stored procedure returns a result set whose fields are mapped to my class’s properties. The stored procedure has pretty complex PL/SQL and it cannot be moved over to a view. Is it possible?
Thanks
Hi,
To be more specific; the stored procedure returns a result-set with multiple rows. I need a collection of the business entities from the mapping.
Thanks
@Saurabh:
Investigate the whole universe of ‘ResultTransformer’ options that are available in the Criteria API (e.g., AliasToResultBeanTransformer, etc.); one or more of these can be used to accomplish what you’re after (mapping of values retrieved from the database into one of your objects).
This is the same (overall) approach that I employed in one of my earlier sessions to ‘cast’ the otherwie untyped multi-dimensional arrays of object[] results to a strongly-typed IList as part of the query — the ResultTransformers are much more capable that the (very) rudimentary approach that I used in the screencast however. Since this series is Nhib ‘fundamentals’, I didn’t want to over-complicate the coding techniques that I’m using here.
Hope this gets you off in the right direction.
@Saurabh:
Sorry, that’s backwards (of course); its name is ‘AliasToBeanResultTransformer’ (not ‘AliasToResultBeanTransformer’) and is explained best in detail here in the Java Hibernate docs at…
http://www.hibernate.org/hib_docs/v3/api/org/hibernate/transform/AliasToBeanResultTransformer.html
Best of luck~!
Thanks again for your great video. About the content, in the next sessions could you talk this kind of “problems”.
1. About the transaction you say “always”, it’s always for delete, update, insert, ok that’s normal but the select ?
2. How NHibernate can : generate a database, update a database, how manage when I have an application and
an update db to do from this application, I have to create new fields, tables, … My customers are may be not (probably not) able to run an SQL script
3. How interact correctly with a grid (or other) and the data access layer
4. When I launch my application (winforms) how check with NHiberate if the database exist, accessible, up to date …
Man, really thanks! Iยดm so excited to watch when you get about session handling in winforms applications !
@Gabriel:
1) In NHib 1.2 transactions are optional in all cases but RECOMMENDED in everything but SELECTs for all the good design reasons that we already understand. In NHib 2.x transactions are MANDATORY in EVERYTHING so I am (generally) changing my Nhib implementation ‘style’ (patten!) to be more inline with the 2.x -pattern of interacting with the session(s) to use tx semantics ALWAYS in order to facilitte easier transition to 2.x when it gets out of RC and into full-release.
2) You’re in luck on this one — its the topic of the (presently-planned) final session I am including in the series about slaving the entire DB schema to one’s Domain Object model, creating and updating the DB schema based solely on the content of your .hbm.xml files, so be patient — its coming 2 or 3 sessions from now ๐
3) This one is really simple — the .NET datagrid control will let you bind it to an IList and its columns to props of the entities in the IList collection. Give it a try — it works.
4) There isn’t (per se) any special way to tell if the DB is either accessible or up-to-date when your app spins up, but here’s a strategy we employ (typically) to accomplish both in one shot…
On app load, attempt a query (using Nhib) against the DB to request a value from a table in the DB that contains a ‘DBVersion’ field and just check this against whatever value this version of your app expects to find there. If you get back < current-expected-DB-version then provide that message back to the user (e.g., "You need to update your DB schema for this version of the application" or whatever). Attempt this operation in a try-catch block that catches the exception raised when the DB cannot be connected to at all and in the catch use that to report back to the user "Sorry, can't get to DB, check your config, conn string, DB creds, whatever". Tends to work fine; then you just need to ensure that whatever DDL script (or whatever) you are having clients use to update their schema also performs an UPDATE on the DBVersion field to set it to whatever value is appropriate to indicate the schema version of the present DB. This is just good practice anyway -- you should always be versioning your DB schema just like you do your app to address just such challenges as this.
“Final session” – “2 or 3 sessions” … Steve are you lazy lol? The end of summer it’s in 7 weeks. Not possible to do a “Fall of NHibernate” ๐ Thanks for you hard work.
Steve,
I am actually trying to work with the mapping and get the collection loaded.
E.g.
call PKG.GetEvents :id
This how ever does not work. If I replace this query call with a SELECT statement, things start to work. The stored procedure is defined to return a REF CURSOR and the cursor is defined as the first parameter in the stored procedure. There is very little documentation available on calling the Oracle stored procedure’s.
Any help would be appreciated.
Thanks
Hi,
The xml content was not displayed correctly. Here it is..
{ call PKG.GetEvents(:Events) }
Sorry for the third post in a row. Basically it is the load-collection tag inside the sql-query tag.
@Saurabh:
You might do better with this on the Nhibernate Users Google Group (http://groups.google.com/group/nhusers) — there is a very active community there of NHib users and that group is also frequented by some of the NHib code authors and contributors.
I don’t personally have much experience trying to do what you’re suggesting (trying to interact with ‘live’ server-side DB cursor in sprocs from inside NHib mapping files) so I’m afraid the specifics of your issue are a bit out of my areas of expertise.
There should be enough people on that forum that SOMEONE will have some thoughts to offer you on this — even if they tell you “sorry, not supported” you will at least KNOW that there isn’t any way to achieve what you’re after here.
Hope this helps~!
@Gabriel:
FWIW, I consider the ‘summer’ to run from Memorial Day at the end of May to Labor Day at the beginning of September — a *VERY* Amero-centric view of the world, I will be the first to admit ๐ but that’s how I’ve always looked at it.
By this calendar (which I completely admit isn’t *really* the end of the summer on a meteorological level), there are only about 2-3 weeks left in my ‘summer’ and that actually properly correlates with my original planned ‘curriculum’ for the Summer of NHibernate series.
All kidding aside, there may indeed be a ‘Autumn of NHibernate’ series that digs into advanced topics; the present series was so well-received by the community that I am considering it but at this point its just a thought in my head without any substance/planning behind it.
I also have some other alternate ideas for an ‘Autumn of‘ series as…
1) Autumn of Windsor (intro and use of Windsor IoC)
2) Autumn of the Basics (including Unit Testing, Mocking, TDD, setting up and working with CI, working in teams, understanding Agile project practices, interacting with Source Control — branching, merging — etc.)
I also have an idea about doing nothing and relaxing a bit, but that seems kinda selfish to me ๐
<>
This would get my vote, closely followed by a “Winter of IoC” (Spring v Windsor, etc)
As a seasoned and experienced developer who has been caught in a non-code design only world for the past couple of years I am eager as hell to pick up on the alt.NET landscape and this series on NHibernate has been excellent.
My real problem now is how I implement this solution in a Best Practice means in ASP.NET for real world Web Apps. I need to get my head around simple things like how the ISession context works (or likely doesn’t) when the Entity objects are being played with remotely via Web Service calls and then passed back.
Oooh… odd. Sorry I meant to say that the following would get my vote
>> 2) Autumn of the Basics (including Unit Testing, Mocking, TDD, setting up and working with CI, working in teams, understanding Agile project practices, interacting with Source Control โ branching, merging โ etc.)
The storm was probably a message/warning from the Entity Framework guys, they have very good connections ๐
This series is great! I’m new to NHibernate and these screencasts will make me an expert. Well, at least that’s what it will say on my resume ๐
I’m wondering why you/anyone would use the criteria API since HQL seems more natural to me. The only reason I can think of is that it will allow you to pass a collection/array/whatever of criteria to a method and dynamically build the statement. Am I missing something else ?
I’ve been playing with the sample code that you provided and I’m running into problems trying to query an object with multiple child-collections using the criteria API.
e.g. Select Customers which have Orders where Order.Orderdate > somedate AND have Pets where Pet.Type = ‘cat’
From my limited understanding .. if I do
.CreateCriteria(“Orders”)
.Add(Expression. …
and then
.CreateCriteria(“Pets”)
.Add(Expression. ….
.. it will assume that ‘Pets’ is a child collection of ‘Orders’.
How do I specify that ‘Pets’ is a child-collection’ of customer instead of orders?
‘Autumn of the Basics’ /’Winter of IoC’ gets my vote as well. With a nice ‘Christmas Special’ of course ๐
I was wondering if you noticed that:
public IList GetDistinctCustomersWithOrdersSince(DateTime orderDate)
{
return session.CreateQuery(“select distinct c from Customer c, c.Orders.elements o where o.OrderDate > :orderDate”)
.SetDateTime(“orderDate”, orderDate)
.List();
}
Brings back Customers who have orders that match the criteria but that when you go after the orders for the customers returned you get *all* of their orders not just the ones that match the where clause. Here is the SQL that NHibernate generated in my case:
NHibernate: select distinct customer0_.CustomerID as CustomerID0_, customer0_.Version as Version0_, customer0_.FirstName as FirstName0_, customer0_.LastName as LastName0_ from Customer customer0_ inner join [Order] orders1_ on customer0_.CustomerID=orders1_.Customer where (orders1_.OrderDate>@p0 ); @p0 = ’07/04/2008 12:00:00 AM’
NHibernate: SELECT orders0_.Customer as Customer__1_, orders0_.OrderId as OrderId1_, orders0_.OrderId as OrderId1_0_, orders0_.OrderDate as OrderDate1_0_, orders0_.Customer as Customer1_0_ FROM [Order] orders0_ WHERE orders0_.Customer=@p0; @p0 = ‘4’
NHibernate: SELECT orders0_.Customer as Customer__1_, orders0_.OrderId as OrderId1_, orders0_.OrderId as OrderId1_0_, orders0_.OrderDate as OrderDate1_0_, orders0_.Customer as Customer1_0_ FROM [Order] orders0_ WHERE orders0_.Customer=@p0; @p0 = ‘5’
NHibernate: SELECT orders0_.Customer as Customer__1_, orders0_.OrderId as OrderId1_, orders0_.OrderId as OrderId1_0_, orders0_.OrderDate as OrderDate1_0_, orders0_.Customer as Customer1_0_ FROM [Order] orders0_ WHERE orders0_.Customer=@p0; @p0 = ‘6’
NHibernate: SELECT orders0_.Customer as Customer__1_, orders0_.OrderId as OrderId1_, orders0_.OrderId as OrderId1_0_, orders0_.OrderDate as OrderDate1_0_, orders0_.Customer as Customer1_0_ FROM [Order] orders0_ WHERE orders0_.Customer=@p0; @p0 = ‘7’
NHibernate: SELECT orders0_.Customer as Customer__1_, orders0_.OrderId as OrderId1_, orders0_.OrderId as OrderId1_0_, orders0_.OrderDate as OrderDate1_0_, orders0_.Customer as Customer1_0_ FROM [Order] orders0_ WHERE orders0_.Customer=@p0; @p0 = ‘8’
Your test:
foreach (var customer in customers)
{
foreach (var order in customer.Orders)
{
Assert.GreaterThan(order.OrderDate, sinceDate);
}
}
failed with my data. I had to change the test to:
foreach (var customer in customers)
{
Assert.GreaterThan(customer.Orders.Count(x => x.OrderDate > sinceDate), 0);
}
I am poking around the documentation but I was wondering if you knew of a way to get the *lazy* queries to contain the where clause from the original query? And THANKS for a job well done!
@Ray
>
Brings back Customers who have orders that match the criteria but that when you go after the orders for the customers returned you get *all* of their orders not just the ones that match the where clause.
<
Isn’t that what should happen ? If I’d were to develop a ‘Customers who ordered X also ordered Y & Z’ feature, I’d like to see their other orders.
You do have a point regarding the test.
@Ray:
See comments # 14 + 15 on this post:
http://unhandled-exceptions.com/blog/index.php/2008/08/04/summer-of-nhibernate-session-07-exploring-mn-relationships-views-and-components/#comments
The same issue arises in this context too (e.g., all orders are available for all customers returned because the query retuns CUSTOMER objects that satisfy the predicate, not ORDER objects that do).
@one
I can see how that would be handy. In my case I want the customer information but my customers have thousands of orders (I’m pretending) and I *only* want the orders identified in the original query.
@sbolen
Thanks! This helps. In fact, I can see how using your two-step criteria API approach to acquire distinct rows could be used to do what I want.
@one:
The primary reasons for choosing the CriteriaAPI over HQL are (IMHO):
a) intellisense support for syntax (e.g., HQL is just open-a-quote-and-start-freeform-typing)
b) ability to (relatively) easily create different queries based on differnt inputs to one’s methods (e.g., in my screencasts my methods have been pretty simple single-statement-CriteriaAPI methods chained together in a fluent0interface style of statement but in a real app its not uncommon for there to be alot more CriteriaAPI statements and params, settings, etc. assinged to the ICriteria object before one gets around to calling .List() on it.
As a programmer, I was always taught that literal SQL in one’s methods was a code-smell and its not all clear to me how HQL is any better than SQL in that regard (tho its clearly better than SQL in a number of other ways). ANY string-literal anything is a potential area for typos, etc. and so whenever there is an non-string-literal way to accomplish something in my code, I tend to choose that way instead of introducing the chance for a typo or punctuation to get in the way of my work.
@steve
Thanks for your response. I see your point about complex criteria (that’s kinda what I meant by dynamically building the criteria-statement ๐ )
No contest regarding the use of literals of course !
Keep up the good work !
I freaking love your videos, I think you’re f*cking hilarious, and a refreshing change to “now you click this… see how fun that is?”
Thank you.
Oh yeah, and it’s educational. LOL.
Sara:
Glad you’re enjoying the content; its nice to know that my informal approach to teaching is being well-received as something other than the rest of the snoozer training videos out there on other topics ๐
Hi Steve,
i’m on the 6th screen cast…. you have done refactor provider class…. and wondering do we need to flush the _session ? if you are not using?
just curious about how _session working.
thanks and great videos.
@Nisar:
AFAIK, the tx.Commit() call will in fact flush the session (e.g. within an ITransaction scope, .Commit() is semantically equivalent to call ing .Flush() on the ISession instance so you are in fact correct — there isn’t a penalty for the .Flush(), but its not required either.
Good catch.
Hi Steve,
Great series of screen casts. I have a quick question
I get a compile error with the following code
foreach (var c in customers)
{
//TODO: Research the build error
Assert.AreEqual(1, customers.Count(x => x == c));
}
customers.Count(x => x == c)
“The property …Count cannot be used with type arguments.
Any ideas?
Thanks
I forgot the context. The code is my previous comment is in
[Test]
public void CanDistinctGetCustomersWithOrdersSince()
Thanks.
First, thanks for the great screencast series–it’s very helpful!
I’m playing around with a Customes-Orders hierarchy like yours, except on a SQL CE database. My tests are similar to yours, and they pass fine when retrieving orders. But when I run a test with the debugger to get a Customer object and break, I run into a problem. When I try to manually inspect the Orders collection (as you do at 47:00 of this session), I get the following error: “Function evaluation timed out.”
I’m not sure what’s causing this error and it puzzles me, since my test that loads Orders runs fine. It’s only when I inspect and look at orders for a different customer that I get the error.
Any thoughts on what might be causing this, and what I need to do to fix it? Thanks again.
Here’s a little tweak to the “distinct query” via Criteria API resulting in 1 db call (instead of 2):
public IList GetDistinctCustomersWithOrdersSince_Crit2(DateTime orderDate)
{
DetachedCriteria customerIds = DetachedCriteria.For(typeof (Customer))
.SetProjection(
Projections.Distinct(
Projections.ProjectionList()
.Add(Projections.Property(“CustomerId”))
)
)
.CreateCriteria(“Orders”)
.Add(Expression.Gt(“OrderDate”, orderDate));
return _Session.CreateCriteria(typeof(Customer))
.Add(Subqueries.PropertyIn(“CustomerId”, customerIds))
.List();
}
Which resolves to SQL:
exec sp_executesql N’SELECT this_.CustomerId as CustomerId0_0_, this_.Version as Version0_0_, this_.Firstname as Firstname0_0_, this_.Lastname as Lastname0_0_ FROM Customer this_ WHERE this_.CustomerId in (SELECT distinct this_0_.CustomerId as y0_ FROM Customer this_0_ inner join [Order] order1_ on this_0_.CustomerId=order1_.Customer WHERE order1_.OrderDate > @p0)’,N’@p0 datetime’,@p0=’2008-04-01 00:00:00:000′
(found out after reading [url=http://colinramsay.co.uk/diary/2008/01/15/nhibernate-optimising-queries-with-projections/]this[/url])
(Uh oh the > < characters aren’t escaped in post above..)