So, I’m still working on the wife’s website and I caught myself not learning something new on the CRUD operations. I had created a simple LINQ to SQL (L2S) implementation and then thought…wait a tick…I should use Fluent NHibernate! I’ve only heard good things and I had started learning it a while ago and never could get my configuration right. Well this time I did and I’m going to show it to you.
You might want to read this previous post before you continue because it gives the back story and setup of the form. I will be implementing the “//Add to mailing list logic” comment on the first code sample on the previous post. I guess I will start with what that looks like and it uses StructureMap. I will post my implementation of StructureMap in my next post.
[AcceptVerbs(HttpVerbs.Post), ValidateModel(typeof(JoinMailingListForm)), ValidateAntiForgeryToken]
public string JoinMailingList(JoinMailingListForm form)
{
if (!ModelState.IsValid)
return "Invalid Email Address. Please press back or enable JavaScript.";
var subscriber = DependencyRegistrar.Resolve<IMailingListSubscriber>();
subscriber.Subscribe(form.SubscriberEmailAddress);
return "Successfully subscribed.";
}
I basically stole the DependencyRegistrar from the sample code in the ASP.NET MVC in Action book. Great book for those of you that don’t already own it.
Okay, so my IMailingListSubscriber is VERY simple and it looks like this:
Now I did create two implementations of this interface one with L2S and one with Fluent NHibernate. I’m only going to show the NHibernate one, but if you’re interested in how I did the L2S one, you can check out this post. My L2S implementation was basically the same with the AutoMapper and everything.
Let’s get to the fluent greatness!
Here is the implementation with Fluent NHibernate:
public class MailingListSubscriber : IMailingListSubscriber
{
public void Subscribe(string emailAddress)
{
if (SubscriberExists(emailAddress)) return;
using(var session = NHibernateHelper.OpenSession())
using (var tx = session.BeginTransaction())
{
session.Save(new Subscriber(emailAddress));
tx.Commit();
}
}
private static bool SubscriberExists(string emailAddress)
{
using (var session = NHibernateHelper.OpenSession())
using(var tx = session.BeginTransaction())
{
var subscriber = session
.CreateCriteria(typeof (Subscriber))
.Add(Restrictions.Eq("EmailAddress", emailAddress))
.UniqueResult<Subscriber>();
tx.Commit();
return subscriber != null;
}
}
}
So let’s break this down line by line starting with the Subscribe method.
First thing I do is check to see if the email address already exists in the database. If it does, I return and show the success message. If it doesn’t, I continue by opening a NHibernate Session with a NHibernateHelper that I will go into in a minute. I pretty much took it straight off the NHibernate wiki and added the fluent to it. I originally did not have the BeginTransaction call, but NHibernate Profiler suggested that I add it and explained why here. NHibernate Profiler is a TERRIFIC tool and I believe it’s required if you’re going to be using NHibernate.
After the transaction is created, I call the save and pass a new instance of my Subscriber class. Afterward, I commit the transaction.
In the SubscriberExists method, I open a session and begin a transaction.
The next part is NHibernate and not Fluent NHibernate. Basically I’m saying “SELECT * FROM Subscriber WHERE EmailAddress=emailAddress” and the UniqueResult returns the Subscriber object instead of a list. I’m pretty sure I got this syntax from one of the NHibernate videos on TekPub. The actual SQL called by NHibernate copied from NHibernate Profiler looks like this:
SELECT this_.Id as Id0_0_,
this_.Email as Email0_0_,
this_.DateSubscribed as DateSubs3_0_0_
FROM connect.MailingList this_
WHERE this_.Email = 'email@email.com' /* @p0 */
After the query, I commit the tran and return whether or not the email address exists. There is probably a better way to do this with NHibernate, but I have not learned it yet! Let us continue…here’s what the Subscriber class looks like:
public class Subscriber
{
public Subscriber()
{
DateSubscribed = DateTime.Now;
}
public Subscriber(string emailAddress)
{
EmailAddress = emailAddress;
DateSubscribed = DateTime.Now;
}
public virtual Guid Id { get; set; }
public virtual string EmailAddress { get; set; }
public virtual DateTime DateSubscribed { get; set; }
public virtual bool Equals(Subscriber other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(other.EmailAddress, EmailAddress);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof (Subscriber)) return false;
return Equals((Subscriber) obj);
}
public override int GetHashCode()
{
return (EmailAddress != null ? EmailAddress.GetHashCode() : 0);
}
}
Notice there is an empty constructor, which is required by NHibernate. I go ahead and initialize some properties with default values in the constructors. One weird thing that happened when I started debugging is that when my initial test ran, NHibernate crashed in the configuration because I didn’t have an empty constructor. The message was clear when you read it, but at first I thought something was wrong with my configuration and not a class issue. The other thing that is a MUST with NHibernate is making your properties virtual. You will definitely get an error if you forget to add that little word.
So there you have the Subscriber class, now let me show you the SubscriberMap. This map is one of the things that makes Fluent NHibernate AWESOME! Especially if you’re not a fan of XML.
public class SubscriberMap : ClassMap<Subscriber>
{
public SubscriberMap()
{
Table("connect.MailingList");
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.EmailAddress).Column("Email");
Map(x => x.DateSubscribed);
}
}
Basically, what this mapping file says is:
- Use the connect.MailingList table
- The Id is a generated Guid
- The EmailAddress property is a column called Email
- Then there is a property and column called DateSubscribed, which is why Column is not specified
That’s it! Now you’re mapped up from the Subscriber class to the DB table. You’ll notice it inherits from ClassMap<T>, which is in the FluentNHibernate.Mapping namespace. I guess I should mention in order to use Fluent NHibernate, just download it here.
One more thing you gotta do is configure NHibernate…FLUENTLY! So here is the NHibernateHelper that I mentioned earlier.
public class NHibernateHelperAll I’m doing is checking if the session factory exists if it doesn’t, configure and build it. You can read the tutorial that helped me with this setup here and you can watch TekPub’s video on the topic (TekPub Subscription Required) too. What it says is fluenty configure the database with MS SQL 2008 with this connection string from the connectionstring settings of the configuration file with the mapping files from the executing assembly and then build it. Pretty easy!
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
_sessionFactory = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008
.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString")))
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
As always, please let me know if you see anything that I could improve or that I’m doing incorrectly. Thanks for reading!