-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 31 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: Here is how I use NHibernate. How do you use it?
PostPosted: Wed Nov 29, 2006 3:36 pm 
Regular
Regular

Joined: Fri Feb 03, 2006 5:28 pm
Posts: 73
Location: Québec, QC, Canada
Hi,

After reading the hibernate in action book, I decided to do the following:

I have my DomainModel classes like Member.cs, Project.cs, Task.cs, Address.cs, etc etc.

These classes have property and method, but are not involved in retrieving or saving to the DB.

These classes are in DomainModel.dll


I also have another dll called Repositories.dll which contains
MemberRepo.cs which has a Save, Delete, GetById, GetByEmail, GetByFirstname methods to save/retrieve from the DB.

These are all statics classes.


Now, I have a website project with a reference to the two dll.

I also have an HttpModule that will Commit the Nhibernate transaction in PreSendRequestHeaders event of the page.

Anytime I want to create a new object, a member for instance, I do something like

Member m = new Member('Firstname', 'Lastname', 'Email@domain.com');
MemberRepo.Save(m);

and it will be saved in my DB.

When I want to modify a member, I'd do the following:

Member m = MemberRepo.GetById(10); // retrieve the IdMember = 10

m.Firstname = 'NewFirstname';

and it will get saved as well since the CommitTransaction will get call automatically by the HttpModule.


All of this works pretty good. One of the drawback, is that I won't be able to catch any exception from commiting a transaction in my code since it only gets called when all my code has executed. So I have to use global.asax to catch the Application_Error.


As for where I get the ISession object, I created another dll Persistance.dll and use the Factory pattern. I have INHibernateProvider interface that define method like GetSession, CloseSession, BeginTransaction, CommitTransaction, RollbackTransaction and a GetFactory method. From that, I created AspNetNHibernateProvider that implement the interface. It store the Factory/Session into HttpContext.Current.Application and use the singleton pattern so there is only one factory across the application.

I also created WinFormNHibernateProvider which store the factory/session into a static class and again, use the singleton pattern.

In the config file on my app, I tell which of the Provider to use.


I was wondering if this is a good design. I'm hoping other could share their design and/or comment mine.

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 8:04 pm 
Beginner
Beginner

Joined: Wed Nov 29, 2006 5:33 pm
Posts: 28
Location: Chicago, IL
The biggest difference between that and what we did is that we encapsulate all of our repository calls inside the class. Save() is a method on Task that calls TaskRepository.Save(). Read(id) is a class method on Task that calles TaskRepository.Read(id). We did this so that developers using the business objects don't need to know anything about repositories, just business objects.

One idea you might consider about the exceptions is to add an event handler to System.AppDomain.CurrentDomain.UnhandledException. Handling this event should catch just about every unhandled exception, potentially including oddballs that cause IIS to recycle, and at least let you log the fact that it happened so it can be addressed.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 11:01 am 
Newbie

Joined: Sun Nov 26, 2006 5:13 pm
Posts: 10
We do pretty much the exact same thing but we don't use static methods in our Repository classes.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 11:42 am 
Regular
Regular

Joined: Fri Feb 03, 2006 5:28 pm
Posts: 73
Location: Québec, QC, Canada
Hi, thanks for the info.

Why not use static classes/methods for repository since you won't access any class members?

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 11:45 am 
Regular
Regular

Joined: Fri Feb 03, 2006 5:28 pm
Posts: 73
Location: Québec, QC, Canada
I also considered having my Save / Read method directly in classes.

As a static method. So I'd do Member.Read(id) which would return an instance of Member.

Can't remember why I didn't use that.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 11:52 am 
Newbie

Joined: Sun Nov 26, 2006 5:13 pm
Posts: 10
I don't like having the CRUD methods in my business classes, but it really comes down to a matter of preference. I like the concept of a Repository which is why I use those and it makes it easier to unit test in my opinion.

I think that castle's active record project uses static methods in their entity base class.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 11:57 am 
Regular
Regular

Joined: Fri Feb 03, 2006 5:28 pm
Posts: 73
Location: Québec, QC, Canada
Great, talking of unit testing..

We want to start doing this. We read a lot about it and I just don't know where to start.

any pointer?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 12:10 pm 
Newbie

Joined: Sun Nov 26, 2006 5:13 pm
Posts: 10
Definitely, I have a few pointers.

If you read a lot of the "agile" stuff they will recommend forgetting about persistence/database until the end of a project. I definitely do not do that. I'm realistic to the fact that a relational database will be in the application and I design that way from the start.

The way we go about unit testing with NHibernate in particular is to use a small embedded database for MOST of our unit tests. SQLite is the database we use in particular, but Firebird or SQL Everywhere are other viable options. I had problem getting SQL Everywhere to work with NHibernate however.

In production, we will end up using a SQL Server database, so we like to abstract the NHibernate config code into a "Database" class. Our unit tests for data stuff typically look something like the following:

// ---------------------------------------------------
// Note :memory: tells SQLite to create the database in memory which
// is very fast and great for unit testing.
// in production this would look like
// Database db = new SQLServerDatabase("Data Source=localhost; ...")
Database db = new SQLiteDatabase(":memory:");

// Create a repository object and pass it our database object
// Database has one method typically, OpenSession() which
// returns a new NHibernate.ISession
UserRepository rep = new UserRepository(db);

// Create a new user domain object and save it
User u = new User("Admin", "Pass");

rep.Save(u);

// Now verify that the user was saved
u = null;
u = rep.FindByUserName("Admin");
Assert.IsNotNull(u);
Assert.AreEqual(u.UserName, "Admin");
Assert.AreEqual(u.Password, "Pass");
// ---------------------------------------------------

You will want to test with a real SQL Server (or whatever your production database will be) for some of your unit tests to make sure that you have that Database connectivity correct. I won't repeat all my db tests for both databases, typically will only do a few basics to make sure CRUD is working. If I notice an bug down the road (there are differences between different databases), I will write a test to prove the bug exists and will fix it. That's about all I can offer right now. Let me know if you have any questions.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 12:19 pm 
Regular
Regular

Joined: Fri Feb 03, 2006 5:28 pm
Posts: 73
Location: Québec, QC, Canada
Ok, the way we are setup right now, won't let me specify a db in my Repository. It's in the hibernate.cfg.xml.

But I get the picture.

Thanks.

Any great book on unit testing?
I've been reading many times Test-Driven Development in Microsoft® .NET.

got another one ?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 12:28 pm 
Regular
Regular

Joined: Fri Feb 03, 2006 5:28 pm
Posts: 73
Location: Québec, QC, Canada
Got one more question :)

Let's say I have a Member class and a Project class.

a Member has a property called Projects which is a collection of project.

what's best:
1- having a helper method AddProject that will be like

AddProject(Project p)
{
p.Member = this;
this._projects.Add(p);
}

or simply use
p.Member = m; // Where m is an instancied Member
m.Projects.Add(p);


I would tend to use the first approach.. but how can I prevent user of my dll to go the second way? How can I make sure they only use the Helper Method?

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 12:46 pm 
Newbie

Joined: Sun Nov 26, 2006 5:13 pm
Posts: 10
I definitely use the first method for a couple reasons.

1. It makes sense logically, a member has multiple projects and knows how to add a project to himself.

2. You will end up forgetting somewhere to set the reference and persistence will fail and everyone will wonder why. If you have the Add method and possibly only expose a read only list, you will prevent these mistakes.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 1:50 pm 
Regular
Regular

Joined: Fri Feb 03, 2006 5:28 pm
Posts: 73
Location: Québec, QC, Canada
that's what I thought. But how do you prevent the programmer to use the second method?

I mean if your class has a private _projects of type List<Project>

even if you have a read-only property, he has acess to the .Add method of the list.

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 1:55 pm 
Newbie

Joined: Sun Nov 26, 2006 5:13 pm
Posts: 10
Not necessarily, you don't have to map NHibernate to your property directly. In other words, you can have Nhibernate map to your inner field (access=field, name="_children" in your mapping file) and then in your class

private IList _children;

and have a property in your class such as

public IList Children
{
// Note - arraylist.readonly can also take an IList param so this works
get { return ArrayList.ReadOnly(_children); }
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 1:59 pm 
Regular
Regular

Joined: Fri Feb 03, 2006 5:28 pm
Posts: 73
Location: Québec, QC, Canada
Ok, I didn't know about ArrayList's readonly feature!

This looks perfect !

so that way, programmer can't call .Add(p); and have to use AddProject();

Thanks for the info!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 30, 2006 2:03 pm 
Newbie

Joined: Sun Nov 26, 2006 5:13 pm
Posts: 10
Yeah I think they can still call Add but an exception is thrown. You can take a look at the docs.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 31 posts ]  Go to page 1, 2, 3  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.