A Quest With EF 4.0 (Entity Framework) And NHibernate Part 2
Usually I don’t really like generated stuff, somehow it seems like I always reach a certain point where I start cursing the $#$%@! wretched generator. So this post will be all about POCO (Plain Old CLR Objects) using just objects. This time I’ll start from the NHibernate Perspective.
Lets consider the following Model (Continuing from my previous post):
It was quite easy to do even with NHibernate – just write a bunch of classes like:
public class User
{
private IList<Category> _categories = new List<Category>();
public virtual string Username { get; set; }
public virtual string Password { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual IList<Category> Categories
{
get { return _categories ; }
set { _categories = value; }
}
}
Write an hbm (mapping) file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
assembly="Sample.DomainModel"
namespace="Sample.DomainModel">
<class name="User" table="Users" >
<id name="Username" length="255" type="System.String" >
<generator class="assigned" />
</id>
<property name="Password" />
<property name="FirstName" />
<property name="LastName" />
<bag name="Categories"
table="UserCategory" >
<key column="Moderators_Username" />
<many-to-many class="User"
not-found="ignore"
column="Categories_Id" />
</bag>
</class>
</hibernate-mapping>
And that's about it, you have a simple and persistable object.
The following test will show you how easy it is to do some basic operations on the User entity I’ve created, such as creating a new one, loading an existing one and deleting the entity
public void CreateAndDeleteUserTest()
{
string username = "myusernamefortest";
string firstName = "SomeFirstName";
using (ISession session = OpenSession())
using (ITransaction trn = session.BeginTransaction())
{
var usr = new User
{
FirstName = firstName,
LastName = "SomeLastName",
Username = username,
Password = "SomePaswword"
};
session.Save(usr);
trn.Commit();
}
using (ISession session = OpenSession())
using (ITransaction trn = session.BeginTransaction())
{
var usr = session.Load<User>(username);
Assert.IsNotNull(usr);
Assert.AreEqual(usr.FirstName, firstName);
session.Delete(usr);
trn.Commit();
}
}
Now, can it be done with EF 4.0?
Let’s have a look:
First I Created a Project called “Sample.DomainModel.POCO” this is where I want to create Persistence Ignorant Objects so I’ve added the following classes:
User, Category, Message and Thread.
And got the following model (quite similar to the one at the beginning of this post):
Now I’ve Created a Project to hold the EDM –> “Sample.DomainModel.EF”
I’ve added an EDM file to the project (Right Click, Add new item, ADO .NET Entity Data Model). and named it SampleModel.edmx.
This time I was a bit lazy (or deferred, if you like the MS jargon) and I’ve chosen to generate the model from the database, In my last post I’ve generated the model from the EDM, so I’ve decided to use the same one.
And following the instructions from the following post in the ADO .NET Team Blog, I’ve done the following on the properties of SampleModel.edmx I’ve erased the CustomTool Entry and left it blank.
Now I’ve added the to “Sample.DomainModel.EF” the ForumsEntities class :
public class ForumsEntities : ObjectContext
{
private ObjectSet<Category> _categories = null;
private ObjectSet<User> _users = null;
private ObjectSet<Thread> _threads = null;
private ObjectSet<Message> _messages = null;
public ForumsEntities()
: base("name=ForumsEntities", "ForumsEntities")
{
_categories = CreateObjectSet<Category>();
_users = CreateObjectSet<User>();
_threads = CreateObjectSet<Thread>();
_messages = CreateObjectSet<Message>();
}
public ForumsEntities(string connectionString)
: base(connectionString, "ForumsEntities")
{
}
public ObjectSet<Category> Categories
{
get
{
return _categories;
}
}
public ObjectSet<User> Users
{
get
{
return _users;
}
}
public ObjectSet<Thread> Threads
{
get
{
return _threads;
}
}
public ObjectSet<Message> Messages
{
get
{
return _messages;
}
}
}
And that's about it. I’ve run the same tests I’ve used in my previous post, and for my surprise it actually worked!
Summing up, at least from the basic point of view it is not that hard now to implement POCO with EF 4.0 which makes it a bit more appealing for me, although from what I’ve read at the ADO .NET team blog there are some issues using POCO in regards to Inheritance when using Proxies (Which is also an issue with NHibernate), Change Tracking, and probably in a real life project some other tweaks will occur.