I am pleased to announce that I have now posted for download the latest installment of the Summer of NHibernate screencast series. In this series we explore NHibernate’s support for many-to-many relationships in both our data and our object model, understand how to interact with views, and investigate some ideas about how to leverage NHibernate’s ‘Component’ modeling to help us avoid the ‘primitive obsession’ anti-pattern in our object model.
I also refactor our tests and our data-access-layer to reflect the introduction of the new Name component to our Customer class.
For the record, I am indeed aware that the results of this refactoring as shown in the screencast (that leads to code like Customer.Name.Firstname) represents a clear violation of the Law of Demeter, but I didn’t want to complicate the object model during the screencast. In a real-world implementation of the Customer class bolstered by the Name class as an NHibernate ‘component’, its likely that this would instead result in a Customer class that looked more like…
public class Customer { //... public virtual string Firstname { get { return _name.Firstname; } set { _name.Firstname = value; } } public virtual string Lastname { get { return _name.Lastname; } set { _name.Lastname = value; } } public virtual string Fullname { get { return _name.Fullname; } }
//...
}
…so that accessing the Customer.Firstname and Customer.Lastname properties would pass-thru to the Customer class’ internal Name instance and the Customer.Fullname property would be a read-only pass-thru to the same-named property of the Name object maintained by the Customer. In this way, consumers of the Customer class need not be aware of the presence of the Name class within the Customer class at all but would still benefit from the ‘richness’ provided by the Name class’ behavior.
Of course, it also now dawns on me that if I had proceeded that way in the screencast, none of the NHibernateDataProvider or NHibernateDataProviderTest methods would have had to have been touched since in a sense the Customer interface wouldn’t have actually changed . Just some thoughts to consider~!
Technical Changes
This installment also represents the first that incorporates a few of the technical changes that have been requested by various people in prior feedback:
- the file format has been changed to wmv (windows media, video) so that (as requested by some) it can be watched @ 1.5x speed in Windows Media Player (hey, whatever works for you –! )
- I’ve changed my VS IDE font selection from Courier New to Lucida Console; this change should result in the code in the editor being a bit easier to read without my needing to increase the point size at all (and take up too much more screen real estate)
As always, comments, feedback, etc. are appreciated.
Hello Steve,
I think there is a technical problem with the sound. On the same PC, no problem from session 1 to 6. But with this session 7, when I put my headphone (Sennheiser PX 100), no sound. I play with WMP11 and tried to VCL same. I have a logitech kit X-530 and without the headphone the sound come from the front only. The others MP3, .avi … work fine. You probably change something ….. If you want to do some sample to test for the next session, you know my email. Regards,
@Gabriel:
That’s what I get for listening to viewer feedback π
So that I’m clear on this, am I understanding that you’re reporting that without your headphones the sound comes out of what — your laptop’s built-in speaker but that with the headphones plugged in you get zero sound out of anywhere?
Its true that I did change the file format (e.g., from AVI to WMV) but when I play the Session 07 file I do successfully get sound on my end (each of two computers I’ve tested on — my laptop with its internal speakers and my desktop PC with its SoundBlaster XFi and extenal speakers). Can you check your cables (and audio settings) and try again for me?
Also, does anyone else have any issues with the sound in this latest installment –? Please let me know and I can re-encode it if needed, but (and I REALLY hate to say this line as a developer) “It works fine on my machine” π
I just downloaded the 7th cast and sound comes out just fine.
Maybe Gabriel has some problems with his audio. I am using WMP 9. I also played it in VLC and have no problem.
By the way, thanks a lot Steve, this is one hell of a series. Cant wait until the next.
@Vinay:
Thanks for the positive feedback; I’m glad you’re finding value in the content. Re: Gabriel’s issue, I actually think that in my communicating with him via e-mail directly we MAY have isolated his issue — it seems as though he has trouble when watching this installment in Vista yet its fine under XP so we’re thinking it may either be a difference in the codec under Vista or a difference in the WMP under Vista.
By chance, are you (or anyone else) having either success or failure listing to session 07 under Vista…?
Works fine for me on Vista.
Maybe he should try downloading a Vista Codec Pack.
Did anyone realize that the video is getting a little time shifted at the end?
Time Shifted
I mean that the sound is not in sync with the Video.
Hi Steve – sound is fine here (no headphones), and the change in font makes a HUGE difference for the better – thanks! Can’t wait for the next installment(s)! π
Cheers, Marc
Well …
I received my new hard drive today. Then I have the “chance” to reinstall Vista from scratch. And you know what ? …. the sound is good on the session 7. But I can tell you something : “I didn’t change anything on my machine” π
@Marc:
Thanks for the extra info (on both the sound and the font). Glad it helps~!
@Gabriel:
Be careful on re-installing Vista; if you re-install your Vista OS more than once a quarter, I think you become an honorary MAC owner π
Seriously tho, I’m glad that (something!) fixed it~!
For fun, let’s see how close people actually watch these screencasts — can you spot the embarrasing logic error in the CanGetCustomersWithOrdersHavingProduct() test method?
@sbohlen
Too scared to point out the errors in case you tell me it was deliberate again π
re: errors, iirc you seem to state that SQL doesn’t have updateable views. Which is untrue, the only limitation is that you can only update to one underlying view table at a time(Or use Instead of Triggers to circumvent this)
With regard to views in general I’d love to hear your opinion on how they fit in with a DDD approach.. views get a bit close to datasets for my liking and overuse may bring some of the same disadvantages. Being new to NH i’m constantly thinking of how I can apply it to existing brownfield projects i’m involved in and of course they usually have many procs and views that bring back columns from multiple source tables, creating a DTO for every one of these seems excessive but i’m sure it’d be more performant than mapping it to single table inspired DTO’s.
Also can you map DTO to more than one table with NH? (not as a relation but where property a comes from table and and property b from table b)
Sorry i’m rambling..
I have a problem/question with the interaction with Winforms.
I take the Steve example (Customer and Order) tables. when I get an Customer, I have the customer info and the Orders, this Orders it’s an ISet. In a Winforms application, I’d like display these orders for a specific Customer.
In the debugger, I see the orders but when I try to bind to a datagridview, this grid view is empty. I tried some suggestions from nhusers google groups but impossible to display theses orders.
Then I tried to display the full list of Customer (the method return an IList and no problem I see them.
I may be not use the NHibernate mechanism correctly. I’d like to do a very small application based on steve database and have a classic master/detail, list of customer in a grid, with a grid with all the orders and the customer’s details and ….. how (the best way) to edit/update.
Hi
I think the CanGetCustomersWithOrdersHavingProduct() test is wrong. It currently tests whether the returned collection has at least one customer with orders with given product, however, it’s meant to assert that all returned customers have orders with that product.
And a question: As I understand, each customer returned from GetCustomersWithOrdersHavingProduct() will not have a list of all its orders, just the ones that contain given product, am I right?
Thanks for great series and thanks for changing the format to WMV, playing it at higher speed can sometimes be helpful.
@Artur:
You are correct — that’s indeed the error. We’ll correct in step 1 of the next installment π
To your question, actually NO, the way its written presently will return CUSTOMER objects (that’s why ‘typeof(Customer)’ is specified as the initial CreateCriteria call) that satisfy the condition. These CUSTOMER instances have collections of ALL their orders. That’s one of the differences between NHib traversing object collections vs. JOINs in SQL.
To get just the ORDERs that have PRODUCTs matching the constraint would require re-writing the query in one of a couple of ways, the most obvious would be to do CreateCriteria(typeof(DataTransfer.Order)) and then traverse from the ORDER objects to their related CUSTOMER instances, but there are a large number of other ways to achieve this too.
PS: Glad you’re liking the WMV format.
Steve,
thanks a lot for this great series. Very clear and understandable all the way through. For me, the learning by example method is very effective. Sure, there’s a lot of details that’s needed before one is an expert NH user, but this kickstart is invaluable.
It well deserves a donation!
@tab:
Thanks for the feedback; as you suggest this series isn’t designed to cover everything one needs to use NHibernate EVER, just the foundational basics needed to get people able to effectively use it in perhaps the 80%-case. Further learning from sources a lot more comprehensive that this one are definitely proscribed for anyone serious about NHib in their app.
Steve,
Fantastic series!!!
I think there is an error on the view; it seems your SQL is joining c.CustomerID with o.OrderId, instead of using o.Customer
Regards,
Nicolas.
@Michael:
Sorry took some time to reply, but I missed your comment there — I try to reply to most all of them but somehow overlooked yours.
Re: updateable views in SQL Server, yes you’re correct that this is possible, but it sort of flies in the face of most practices and certainly isn’t DB-portable (which is why I tend to shy away from it as a practice). You are correct that my statement on its face is indeed in error (or at least misleading π )
Re: Views in general as they apply to DDD, clearly there’s not MUCH need for a domain Entity that’s normal use is read-only so generally views tend to have no place in the representation of domain entitties but I have used them in the past in some corner case situations. They remain a tool in my toolbelt though one that is less-often implemented.
Re: mapping DTO to more than one class NOT as a relation, there isn’t QUITE a way to do this in NHibernate though there SORT OF is. If by ‘not as a relation’ you mean ‘not as a collection within the object model’, then YES this can be done useing the mapping tag and its semantics. But if you by ‘not as a relation’ you mean ‘where this isn’t a relation between the two tables in the database from which the values come’ then, NO, since there would HAVE to be some way for NHib to traverse from the record with Identity in the first table to the related single record in the second (or third, fourth, fifth, etc.) table. Again, google on to get a sense of how one might accomplish this and also look around for info on ‘table-per-subclass’ inheritance modeling as this is sort of the same area of focus.
Hope this helps.
@Michael:
Seems that the angle-brackets from my prior comment (#19) were stripped out of the comment. The mapping tag that I was TRYING to suggest you investigate there is called ‘joined-subclass’. In the prior post, every time the sentence doesn’t seem to make sense, insert the text ‘joined-subclass’ into the sentence and it will be fine π
WordPress seems to want to strip angle-brackets out of comments, presumably to protect me from aberrent HTML entered as comments.
hi Steve,
if i understood correctly the purpose of using “view” is for “read only”?
great videos and learn a lot and today whole day i was watching your videos and i’m on 8th video now π
@Nisar:
You are correct (sort of). Various DB platforms have varying support for what are called ‘updateable views’ where you can actually use a view as a read-write target instead of just a read-only target. Different DB targets impose different constraints on what must be ‘true’ for a view to be updateable and still other DB platforms don’t support updateable views at all.
Given all this, unless you are 100% certain of the DB your NHib-based app will run against, its really best-practice not to make a design decision (like to depend on updateable views) unless you are willing to sacrifice DB-platform-neutrality (one of the main reasons for selecting and O/RM tool like NHib in the first place).
That said, if you decide that tying your solution to a particular DB target is OK for your app, then google on NHibernate + + “updateable view” and you will certainly find plenty of info out there.
@Nissar:
In comment #22 WordPress stripped out my thing-in-anglebrackets in that last sentence that was supposed to read “NHhibernate + your-database-here + updateable view”.
I keep forgetting that WordPress just drops anything that contains HTML-style angle brackets π
Hi Steve,
This screencast touches immutability a little so here is the most apt place to ask the following question:
I am currently tasked with introducing NHibernate into our codebase. All of our business domain objects are immutable and take the following format:
public class SampleEntity
{
public readonly int SampleProperty;
public readonly string SampleProperty2;
public SampleEntity(int sp1, string sp2)
{
this.SampleProperty = sp1;
this.SampleProperty2 = sp2;
}
From what I can see, we would have to perform the following to make our entites NHibernate compatible but as close as possible to still being immutable “enough”:
1. Add a default constructor (it can be private but still needs to be added)
2. Take the readonly attribute off all properties and have get; private set; accessibility.
Is there any way to get NHibernate to work with an antity of the type described above?
In my opinion, we shoudnt have to sacrifice our business domain objects “immutability” to cater for an ORM integration.
Also, I know another solution could be to map our immutable business domain entities to NHibernate compatible entities but this in my opinion would be too costly!
So in conclusion , is there a way to get HNibernate to work for “truely” (i.e. using readonly properties) immutable types?
@Billy:
You are (I think) in luck. Step 1 you have already identified as being to make the default (empty) constructor private. Step 2 however is to do something that I didn’t begin to go into in any of the screencasts: tell nhib to use the private backing fields for your properties instead of the properties themselves.
You need a combination of access=”field” on your property, id, etc. tags and also investigate ‘naming strategies’ so that nhib can properly deduce the name of your backing fields from your property names. This set of steps will allow nhib to access your underlying private data members NOT via your property accessors.
[…] day 1: An Open Source Project Called βFailure:β Community … saved by tkoudsi2009-03-13 – Summer of NHibernate Session 07: Exploring m:n Relationships … saved by htrstaff2009-03-12 – Joining the Mobile Computing Masses; Visual Studio 2005 and Vista […]
Hi there. I’m following your videos and trying to learn NHibernate.
I’m trying to use NHibernate with a MS Access DB. I’ve got the basics building, but when it comes to a many-to-many relationship I get some strange exception messages.
Let’s take your many-to-many example. You have there the tables Order, OrderProduct and Product. I have similar tables. I’ve made the hbm.xml files and the classes exactly the same as you did, everything compiling. I’m retrieving an order from the DB by the Id, but when I’m trying to see, let’s say, all products in a given order, I get this message when looking to the Products collection of the Order class:
{“could not initialize a collection: [FECCGe.Core.Student.Domains#1][SQL: SELECT domains0_.ID_Student as ID2_1_, domains0_.ID_Materie as ID1_1_, domain1_.ID_Materie as ID1_1_0_, domain1_.Materie as Materie1_0_, domain1_.ID_Specializare as ID3_1_0_, domain1_.AnUniversitar as AnUniver4_1_0_ FROM Student_Materie domains0_ left outer join Materie domain1_ on domains0_.ID_Materie=domain1_.ID_Materie WHERE domains0_.ID_Student=?]”} System.Exception {NHibernate.Exceptions.GenericADOException}
and it’s inner exception message is : “No value given for one or more required parameters.” and as you see for yourself, I don’t parse anything for the ID_Student column.
The way I’m retrieving the Order (like in your example) is this :
return _session.Get(studentId);
Do you know what’s wrong or am I doing something wrong with NHibernate.
Please answer, it’s kind of urgent ! π
@Sorin:
If your need is urgent, you might have better luck on the NHUsers forum where there are more people can assist you ( http://groups.google.com/group/nhusers ).
I can advise in advance that you’re going to need to be able to provide some or all of the following in order for either myself or anyone else to be able to assist you:
* class file(s) for persisted objects
* mapping (.hbm) files for objects
Best of luck~!
-Steve B.
Elo, I’m a newby. Thought I’d say hi.
Take care and Thanks alot
(sorry if the wrong place to post)
I am new to Nhibernate and was going through the Summer of Nhibenate videos. I have a doubt regarding lazy load.
Say I have a Customer Class which has a list of order.
class customer {
public IList orders
}
I know we can fetch all the customers having order_date > ’30-Sep-2013′ but then can we get all these orders populated in order collection as well using lazy load.
Customer table
customer_ID customer_name
1 Customer1
2 Customer2
3 Customer3
Order table
orderid customer_id order_date
1 1 1-Sep-2013
2 1 1-Nov-2013
3 2 1-Sep-2013
4 2 1-Sep-2013
5 2 1-Nov-2013
6 2 1-Nov-2013
the hql used is
select distinct customer c , customer.order.elements o where o.order_date >’30-Sep-2013′
This will return customer 1 and 2.
SO I have the following doubts :
What would customer.order collection contain when being fetched in a lazy load scenario?
Will it have all the orders or it will use the where clause (order_date > ’30-Sep-2013′) criteria of hql?
If not is there any other way I can do this using lazy load?