Login or Sign Up to become a member!

EXPERTS, INFORMATION, IDEAS & KNOWLEDGE

Social bookmarker Add this

Your profile

Search

November 2008
Mon Tue Wed Thu Fri Sat Sun
 << <   > >>
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

XML Feeds

Tags: unit testing

All the LessThanDot Journals

The donkey and unit testing

by chrissie1


Permalink 21 Nov 2008 03:55 , Categories: Introduction to Architecture & Design Tags: donkey bump, unit testing

In dutch there is this saying.

Een ezel stoot zich nooit tweemaal aan dezelfde steen.

A literal translation would go like this.

A donkey never bumps into the same stone twice.

or

Even a donkey does not bump himself twice against the same stone…

A less literal translation would be this.

Fool me once, shame on you. fool me twice, shame on me.

So unit testing is all about being the donkey or the fool or both ;-).

3 comments »Send a trackback » 163 views

An interview with Roy Osherove author of "The Art of Unit Testing"

by chrissie1


Permalink 12 Oct 2008 09:47 , Categories: Designing Software, Enterprise Architecture, Introduction to Architecture & Design Tags: interview, roy osherove, unit testing

Today I will be having an interview with Roy Osherove about his upcoming book “The Art of Unit Testing“. The book concentrates on unit testing for the .Net developer. And it covers these subjects (as taken from the manning website).

* Introduction to unit testing and the basics of writing real-world unit tests with NUnit
* Best practices for writing maintainable, trustworthy, readable tests
* Mock Objects and integration testing in-depth
* Reference chapters for NUnit, Rhino.Mocks, and TypeMock.NET
* Database unit testing
* Testing legacy code
* Designing for testability

You can wait for the hard copy to come out in the beginning of 2009 or buy the Early access edition now.

1. Do you think unit-testing is for the beginner level user or for the advanced level user? And is your book geared toward the beginner level unit-tester, the more advanced level unit-tester or the what-is-unit-testing user?

Unit Testing is the basic activity that any developer should be involved with, from entry level to the most advanced.
It should be as natural to do as debugging is, and should be viewed as part of daily life for developers. My book is geared towards three crowds: Those who don’t even know what unit testing is, those who do but want to learn how to write good tests, and those who have experience and would like to advance it deepen it.
The book strictly deals with Unit testing, not test driven development.


2. Do you think schools should teach more and better unit-testing skills or is that something a developer should learn on the job? And how long does it take to become a good unit-tester?

I think unit testing should be a skill that is taught in schools. Absolutely. I think that is far from happening though…
Learning the basics of unit testing (the API) takes an hour, not more. Learning the basic three pillars - maintainable, readable and trustworthy takes longer, mostly on the job. but you’d need to have guidelines to follow.
it’s a bit like asking how long it takes to learn good coding conventions. It’s on the job training but you need to have guidance.
That said, I think that learning how to use a mocking framework, the idea of mock and stub, dependency injection and such can take a while, several weeks of getting used to things. without guidance - much longer. I’m hoping that with frameworks like Typemock Isolator this barrier will grow smaller and smaller.

3. What do you think will be the future of unit-testing? Will it be TDD or more BDD? Will it be wizard driven? For example, you write a small block of code, click generate and the system writes your tests? Will MS-Test become the standard?

I think we will see more BDD-like syntax trying to emerge (right now it is very chaotic and confusing to me). I think We will see more tooling around unit testing such as Pex, MbUnit\Gallio\Typemock Isolator etc.. and less focus on basic APIs. Model based testing and DSLs for testing will try to take a bigger role.
MS test will become more and more prevalent and we will see more standardization in unit testing and mocking frameworks just like we start to see in the IoC space (IServicceLocator).
wizard based test generators will be more prevalent, I think.

4. How important is the role of Microsoft in all this? Will more emphasis from them help the community do more unit-testing? Or is the RAD/Wizard Driven development community to strong?

Microsoft having unit testing in the box is a big help towards making this ubiquitous. I don’t think that the RAD\Wizard driven community is at odds with having unit tests. Instead, we should be making unit testing easier to accomplish. right now the barrier is too high for most people. That does not mean they are bad programmers because they don’t have time or face a lot of organizational difficulties introducing unit testing.
Whenever something is easier to do than not doing it, people will do it. When it becomes easier to just write unit tests for code instead of debugging for 3 days straight to find a small bug, we’ll see the chasm crossed.

5. The .Net world and the unit-testing world seem to be in a constant state of flux. It seems like there is something new to learn every week.
Frameworks change, frameworks are added. How do you handle that change?

I read a lot of blogs, and download lots of zip files.
but I usually don’t stick with something before it becomes a little more mainstream. I might give Moq a try, I might check out Pex, but it will always be a red flag to me until I can make sure it has enough of a following to justify a real usage in a real project (hope grown projects don’t count - they are my playground - and where I learn lots of things)

6. What other resources do you recommend apart from your book to start learning about unit-testing. Can you name a few?

That’s the thing - there aren’t a lot of books that deal with this that don’t also deal with Test Driven Development. I started with reading “Test Driven Development with Microsoft.NET by Jim Newkirk, http://www.testdriven.com is nice. Frankly, I don’t know a good resource on *just* unit testing that does not throw in TDD into the mix. I think that’s a sign that we are coupling the two things too much. Getting started with TDD is much harder than getting started with unit testing.
I am starting a section on “how to get started with Unit Testing” on my book wiki and I’m encouraging people to help out filling information in it.

7. Good unit-testing is about getting maintainable, readable and trustworthy tests. This seems the same for good code. So having good unit-tests means you have good code? Or is it a little more subtle then that?

Unit Tests should be considered part of the production code. they should be refactored and they should have the same qualities, with a little extra on top: because a unit test represents a *usage case* of a piece of code, it should have a more “declarative” quality that can be easily read and reviews. it should show intent.

trust worthy, among other things, means you are sure that you are indeed testing the right thing. that takes care of making sure your code in production actually working, so, yes. in essence, if your tests provide all those qualities, depending in part on the amount of coverage you have, you can be reasonable sure you have good code.
Sadly, all three pillars are all but forgotten in most literature that deals with unit tests

8. What new features do you want in future versions of the .Net framework and your favorite unit testing frameworks?

I don’t have anything specific I can think of right now. I’m looking forward to IronRuby.
In unit test frameworks I think we are pretty much “stuck” where we are and its time to see a new breed of next generation test frameworks that take us a step further. from model based testing to StoryTeller (Fit) and acceptance testing, i hope the next 3 years will be just as exciting as the past 3 were.

9. What did you learn from writing this book? Does writing books come easy to you? Are you planning more books?

I learned that writing a book is pretty hard work, mainly. I’m not planning another book any time soon.
I plan to add any accumulated knowledge in the book’s wiki site (chapters that should have been written…etc)

10. What does the future look like for you? Any conferences, seminars or trade shows perhaps?

In the near future I’ll be speaking TechEd Europe in Barcelona this November. During December and throughout next year I’ll be holding Unit Testing at Test Driven Development Courses throughout Norway. Other than that I’ll continue to work on the next generation of unit testing tools at Typemock.

Thank you Roy for this interview. If people want to learn more about unit testing I invite them to read Roy’s book. And his blog.

Leave a comment »Send a trackback » 1429 views

My Path to the Dark Side part 4 - the Repositories

by AlexCuse


Permalink 28 Jul 2008 07:07 , Categories: Microsoft Technologies, C# Tags: c#, nhibernate, unit testing

Previous posts can be found here:

Setting up the repositories for our objects is where this really starts to get fun for me. This is what allows us to work with the persisted objects so easily from our application code, without all the SQL getting in the way. The first thing we want to think about here is what we need the repository to do. Add/Delete/Update all come to mind of course. As well as retrieval of single objects and collections. These will be pretty much standard behaviors across most of our objects. So lets’ look at the interface first:

  1. using System;
  2. using System.Collections.Generic;
  3. using RecipeTracker.Model;
  4.  
  5. namespace RecipeTracker.Interfaces
  6. {
  7.     public interface IRecipeRepository
  8.     {
  9.         void Add(Recipe recipe);
  10.         void Update(Recipe recipe);
  11.         void Remove(Recipe recipe);
  12.         Recipe GetByID(int id);
  13.         ICollection<Recipe> GetByFamily(string family);
  14.         ICollection<Recipe> GetAll();
  15.         void Dispose();
  16.     }
  17. }

Looking at all those methods, there is really only one (GetByFamily) that we won’t need for any repository that we create. So we can put all the other methods into a BaseRepository class. We will need use generics so we can return all the different types however. But first, we need to get a session, so we can add a class for that.

  1. using System;
  2. using NHibernate;
  3. using NHibernate.Cfg;
  4.  
  5. namespace RecipeTracker.Repositories
  6. {
  7.     public class SessionProvider<T> where T:new()
  8.     {
  9.         private static ISessionFactory _sessionFactory;
  10.  
  11.         private static ISessionFactory SessionFactory
  12.         {
  13.             get
  14.             {
  15.                 if (_sessionFactory == null)
  16.                 {
  17.                     var configuration = new Configuration();
  18.                     configuration.Configure();
  19.                     configuration.AddAssembly(typeof(T).Assembly);
  20.                     _sessionFactory = configuration.BuildSessionFactory();
  21.                 }
  22.  
  23.                 return _sessionFactory;
  24.             }
  25.         }
  26.  
  27.         public static ISession OpenSession()
  28.         {
  29.             return SessionFactory.OpenSession();
  30.         }
  31.     }
  32. }

The SessionFactory part should look familar from part 3, the only difference here is that we are initializing the configuration using TypeOf(T) to determine which assembly to find the configuration in rather than TypeOf(MyType). We could probably get away with the latter for this purpose, because there probably won’t be more than one assembly in the application, but why be lazy right? After all, we do need to use generics to deal with the return types anyways.

So now this little bit of code doesn’t need to be handled by our repository, and it can focus on what it does best. So here’s the BaseRepository, it’s nice and simple since it doesn’t need to get its’ own sessions anymore:

  1. using System;
  2. using System.Collections.Generic;
  3. using NHibernate;
  4. using NHibernate.Cfg;
  5.  
  6. namespace RecipeTracker.Repositories
  7. {
  8.     public abstract class BaseRepository<T> where T: new()
  9.     {
  10.         protected ISession _session = SessionProvider<T>.OpenSession();
  11.  
  12.         public T GetByID(int id)
  13.         {
  14.             return _session.Get<T>(id);
  15.         }
  16.  
  17.         public ICollection<T> GetAll()
  18.         {
  19.             var products = _session
  20.                 .CreateCriteria(typeof(T))
  21.                 .List<T>();
  22.             return products;
  23.         }
  24.  
  25.         public void Update(T toUpdate)
  26.         {
  27.             using (ITransaction transaction = _session.BeginTransaction())
  28.             {
  29.                 _session.Update(toUpdate);
  30.                 transaction.Commit();
  31.             }
  32.         }
  33.  
  34.         public void Add(T toAdd)
  35.         {
  36.             using (ITransaction transaction = _session.BeginTransaction())
  37.             {
  38.                 _session.Save(toAdd);
  39.                 transaction.Commit();
  40.             }
  41.         }
  42.  
  43.         public void Remove(T toRemove)
  44.         {
  45.             using (ITransaction transaction = _session.BeginTransaction())
  46.             {
  47.                 _session.Delete(toRemove);
  48.                 transaction.Commit();
  49.             }
  50.         }
  51.  
  52.         public void Dispose()
  53.         {
  54.             _session.Close();
  55.             _session.Dispose();
  56.         }
  57.     }
  58. }

Now, look how simple that is to do what we need with our object? No building SQL queries, no creating parameter arrays, or anything. A nice simple bit of code that does just what we need it to do, without all the hassles. We just need a session and the simple commands that it offers, and we can do anything we need. Beautiful, right?

But what if we wanted to do something like get all recipes from a certain family? This will be specific to the object type we need, so we can do that in our implementation of the baseclass (hey, gotta have something in there right!). And this is in fact all that our RecipeRepository class has, one method:

  1. using System;
  2. using System.Collections.Generic;
  3. using RecipeTracker.Model;
  4. using NHibernate;
  5.  
  6. namespace RecipeTracker.Repositories
  7. {
  8.     public class RecipeRepository : BaseRepository<Recipe>, Interfaces.IRecipeRepository, IDisposable
  9.     {
  10.         public ICollection<Recipe> GetByFamily(string family)
  11.         {
  12.                 var products = _session
  13.                     .CreateCriteria(typeof(Recipe))
  14.                     .Add(NHibernate.Criterion.Expression.Eq("Family", family))
  15.                     .List<Recipe>();
  16.                 return products;
  17.         }
  18.     }
  19. }

This is some wacky looking code at first. It kind of reminds me of Linq, but what its’ called is HQL (Hibernate Query Language). I haven’t really gotten into it all that much, so I don’t feel qualified to speak about it in detail, but I do find it kinda cool. It may not be as easy as Linq, where you could do a nice Linq query such as

recipeList.Where(n => n.Family = family)

But remember this needs to work on older framework versions as well. I think the HQL is reasonably succinct, and even somewhat elegant. After all reading that you can just about instantly tell what it does. It just creates a criteria on the session for Recipes, and then defines the expression to be evaluated (table.Family = family). Pretty cool. We could probably figure out how to do this with generics pretty easily, but I figure this kind of method is going to be tied to your specific type, and you want to have a descriptive name, and all that.

So after all this I think we are ready to set up some tests. This will be on the next page (damn I’m getting long-winded!)

Pages: 1 · 2

2 comments »Send a trackback » 412 views

My Path to the Dark Side part 3 - Testing the Schema

by AlexCuse


Permalink 21 Jul 2008 09:59 , Categories: Microsoft Technologies, C# Tags: c#, nhibernate, unit testing

Previous posts can be found here:

In part two we set up our domain model. Now, before we can test nhibernate’s ability to work with and persist objects, we need to ensure that we’ve defined our schema well enough that NHibernate can create the Schema for us (since that was kind of the point). Now is where NUnit starts to become very useful.

First step we’re going to take to set up NUnit is to add another project to our solution. I named this project the very creative RecipeTracker.Tests. When setting up this project, it is important to add all the same references as we used in the main project. In addition we need to add a reference to the main project itself and a reference to nunit.framework. For the main project, we’ll need to again set the “CopyLocal” option to true. Finally, we also need a copy of our Sql Compact database in this project.

Our first unit test will just be to see that we can export the schema. Here it is:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using NHibernate.Cfg;
  6. using NHibernate.Tool.hbm2ddl;
  7. using NUnit.Framework;
  8. using RecipeTrackerPartOne;
  9.  
  10. namespace RecipeTrackerPartOne.Tests
  11. {
  12.     [TestFixture]
  13.     public class GenerateSchema_Fixture
  14.     {
  15.         [Test]
  16.         public void Can_generate_schema()
  17.         {
  18.             var cfg = new Configuration();
  19.             cfg.Configure();
  20.             cfg.AddAssembly(typeof(Model.Recipe).Assembly);
  21.  
  22.             new SchemaExport(cfg).Execute(false, true, false, false);
  23.         }
  24.     }
  25. }

There’s a lot of new stuff going on here. Most noticeable is the directive to use nunit.framework, and the attributes added to our class and our methods. These attributes are used when we load the project into NUnit, so that the NUnit application knows which code to execute as a test. We need to identify our class as a TestFixture, then our method within the class as a Test (this setup allows us to include supporting code that is not necessarily a test). Also notable is the directive to use NHibernate.Tool.hbm2ddl. This is what allows NHibernate to create the schema for us (by converting Hibernate mappings to Data Definition Language).

The most interesting line, as far as I am concerned, is the “AddAssembly” line. This is what associates our Configuration with a given assembly, and therefore that assembly’s hibernate.cfg.xml file. So, what we are really testing here is really the schema we have defined in the xml file.

If everything is set up right, when you fire up the NUnit GUI, load the RecipeTracker.Tests assembly, and run the test, you should see a nice green bar. Unfortunately, we broke the first rule of Unit Testing, that the first time we run a test it should fail. Well, I didn’t, but I wanted to spare you gentle readers some of the pain of wrestling with the mapping file. But fear not, because now it is time to experience the joy that is the red, “you screwed up” bar. Remember, we want to confirm that NUnit will in fact tell us when we do screw up!

For this part we’ll need to start setting up our repositories to move the objects to and from the database. This gets pretty involved, so this will have to be continued in Part 4.

Here is the sample project (so far). Next one will be where it gets interesting! Sample Project - Part 1

Leave a comment »Send a trackback » 277 views

My Path to the Dark Side part 2 - The Domain Model

by AlexCuse


Permalink 15 Jul 2008 06:24 , Categories: Microsoft Technologies, C# Tags: c#, nhibernate, unit testing

In part one we discussed what has brought me to the shameful point of using an object-relational mapper. At the risk of being ostracized from the database community, I really think this is going to be helpful for my project.

The next step is to actually build up the domain model, and set up the mappings for NHibernate. I won’t be pasting all the code in here, but I will be attaching the project itself to the next post if anyone’s interested. I ended up working ahead of myself so I had to kind of go backwards to create a “part one” project (I got too carried away with working, forgot to check in for a few days :( ). First let us look at the “recipe” domain object, which is at the center of everything.

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace RecipeTrackerPartOne.Model
  7. {
  8.     public class Recipe
  9.     {
  10.         private Int32 _id;
  11.         private String _name;
  12.         private DateTime _attemptDate;
  13.         private String _family;
  14.         private String _style;
  15.         private Double _originalGravity;
  16.         private Double _finalGravity;
  17.         private Int32 _boilTime;
  18.         private Int32 _fermentationTime;
  19.         private Int32 _fermentationTemperature;
  20.         private Int32 _secondaryFermentationTime;
  21.         private String _yeast;
  22.         private Int32 _batchSize;
  23.         private String _note;
  24.         private Person _brewer;
  25.  
  26.         //rating info
  27.         private IList<Impression> _recipeImpressions;
  28.  
  29.  
  30.         //list of ingredients
  31.         private IList<Ingredient> _ingredientsUsed;
  32.  
  33.         public Recipe()
  34.         {
  35.             _recipeImpressions = new List<Recipe>();
  36.             _ingredientsUsed = new List<Recipe>();
  37.         }
  38.  
  39.         public Int32 Id
  40.         {
  41.             get { return _id; }
  42.             set { _id = value; }
  43.         }
  44.  
  45.         public String Name
  46.         {
  47.             get { return _name; }
  48.             set { _name = value; }
  49.         }
  50.  
  51.         public DateTime AttemptDate
  52.         {
  53.             get { return _attemptDate; }
  54.             set { _attemptDate = value; }
  55.         }
  56.  
  57.         public String Family
  58.         {
  59.             get { return _family; }
  60.             set { _family = value; }
  61.         }
  62.  
  63.         public String Style
  64.         {
  65.             get { return _style; }
  66.             set { _style = value; }
  67.         }
  68.  
  69.         public Double OriginalGravity
  70.         {
  71.             get { return _originalGravity; }
  72.             set { _originalGravity = value; }
  73.         }
  74.  
  75.         public Double FinalGravity
  76.         {
  77.             get { return _finalGravity; }
  78.             set { _finalGravity = value; }
  79.         }
  80.  
  81.         public Int32 BoilTime
  82.         {
  83.             get { return _boilTime; }
  84.             set { _boilTime = value; }
  85.         }
  86.  
  87.         public Int32 FermentationTime
  88.         {
  89.             get { return _fermentationTime; }
  90.             set { _fermentationTime = value; }
  91.         }
  92.  
  93.         public Int32 FermentationTemperature
  94.         {
  95.             get { return _fermentationTemperature; }
  96.             set { _fermentationTemperature = value; }
  97.         }
  98.  
  99.         public Int32 SecondaryFermentationTime
  100.         {
  101.             get { return _secondaryFermentationTime; }
  102.             set { _secondaryFermentationTime = value; }
  103.         }
  104.  
  105.         public String Yeast
  106.         {
  107.             get { return _yeast; }
  108.             set { _yeast = value; }
  109.         }
  110.  
  111.         public Int32 BatchSize
  112.         {
  113.             get { return _batchSize; }
  114.             set { _batchSize = value; }
  115.         }
  116.  
  117.         public String Note
  118.         {
  119.             get { return _note; }
  120.             set { _note = value; }
  121.         }
  122.  
  123.         public IList<Impression> RecipeImpressions
  124.         {
  125.             get { return _recipeImpressions; }
  126.             set { _recipeImpressions = value; }
  127.         }
  128.  
  129.         public IList<Ingredient> IngredientsUsed
  130.         {
  131.             get { return _ingredientsUsed; }
  132.             set { _ingredientsUsed = value; }
  133.         }
  134.  
  135.         public Person Brewer
  136.         {
  137.             get { return _brewer; }
  138.             set { _brewer = value; }
  139.         }
  140.  
  141.         public void AddIngredient(Model.Ingredient i)
  142.         {
  143.             _ingredientsUsed.Add(i);
  144.         }
  145.  
  146.         public void RemoveIngredient(Model.Ingredient i)
  147.         {
  148.             _ingredientsUsed.Remove(_ingredientsUsed.Single<Model.Ingredient>(x => x == i));
  149.         }
  150.  
  151.         public void AddImpression(Model.Impression i)
  152.         {
  153.             _recipeImpressions.Add(i);
  154.         }
  155.  
  156.         public void ChangeBrewer(Model.Person p)
  157.         {
  158.             _brewer = p;
  159.         }
  160.  
  161.         public Double AlcoholByWeight()
  162.         {
  163.             return (76.08 * Convert.ToDouble(_originalGravity - _finalGravity)) / (1.775 - Convert.ToDouble(_originalGravity));
  164.         }
  165.  
  166.         public Double AlcoholByVolume()
  167.         {
  168.             return AlcoholByWeight() * (Convert.ToDouble(_finalGravity) / 0.794);
  169.         }
  170.     }
  171. }

Its’ a pretty simple object, it has some data, and just a couple methods. The most interesting properties to look at here are RecipeImpressions, IngredientsUsed, and Brewer. Why are these the most interesting? Because each is of another type (Impression, Ingredient, and Person, respectively) that we will need to persist in our database. Now that we’ve got an object in mind, lets’ start thinking about setting this up.

Setting Up The Project

We need to do some housekeeping before we proceed.

First, adding our references to the following:

  • NHibernate (I used the most recent beta version since this is not exactly a critical app)
  • Sql Server Compact (System.Data.SqlServerCe)


Once these references are added, we need to make sure both have their “Copy Local” property set to True (by default this will be false for SqlServerCe).

After adding the references, we need to add a Sql Server Compact database to our project (in the root directory). I called it “BeerRecipes.sdf". You can skip that Data Set Wizard thing that pops up.

Once this is done, we are ready to set up NHibernate.

Setting Up NHibernate Configuration

NHibernate is driven by an xml file added to the project called hibernate.cfg.xml. So what are you waiting for, add that file! (again to the root directory) I promise to be here when you get back. Ok, that was not so hard, right? Now, what do we need to add to this file? For this simple example, not all that much. We need to define a “session-factory” class, which is basically a more sophisticated connection string. Properties we need to set include:

  • Provider
  • Dialect - SQL “flavor” for NHibernate to use
  • Driver - Driver NHibernate uses to identify (and connect to) Provider
  • Connection String - where is the database located?
  • Show Sql - whether to output SQL to the console

So, what does this file look like? Glad you asked:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  3.   <session-factory>
  4.     <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
  5.     <property name="dialect">NHibernate.Dialect.MsSqlCeDialect</property>
  6.     <property name="connection.driver_class">NHibernate.Driver.SqlServerCeDriver</property>
  7.     <property name="connection.connection_string">Data Source=BeerRecipes.sdf</property>
  8.     <property name="show_sql">true</property>
  9.   </session-factory>
  10. </hibernate-configuration>

For the most part these are pretty self explanatory. The only one I’ve really been messing with is the “show_sql” property, which controls whether the sql generated by NHibernate is output to the console or not. I like to set this to true when I am running my unit tests manually, so I can look at the SQL in case a test fails. Otherwise, I would set it to false.

Setting up NHibernate Mappings

This is where it gets interesting. We now need to tell NHibernate which tables within the database to store our objects in, and define any relationships between the objects. We also need to tell NHibernate which assembly to look for our types in. We’ll do this in a mappings file. I created a special “mappings” folder within the project for this. The naming convention for these files is myfile.hbm.xml. Because I’m lazy I just created one file, called RecipeMappings.hbm.xml and threw everything in there. So lets’ just get the whole thing on the table first, then talk about it (only 2 classes included for brevity’s sake, but they’re all there I swear).

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
  3.                    assembly="RecipeTracker"
  4.                    namespace="RecipeTracker.Model">
  5.  
  6.   <class name="Recipe" table="Recipes">
  7.     <id name="Id" column="Id" type="Int32">
  8.       <generator class="native" />
  9.     </id>
  10.     <property name="Name" type="String(35)"/>
  11.     <!– we can also do without specifycing type and let nhibernate do the work–>
  12.     <property name="AttemptDate"/>
  13.     <property name="Family"/>
  14.     <property name="Style"/>
  15.     <property name="OriginalGravity"/>
  16.     <property name="FinalGravity"/>
  17.     <property name="BoilTime"/>
  18.     <property name="FermentationTime"/>
  19.     <property name="FermentationTemperature"/>
  20.     <property name="SecondaryFermentationTime"/>
  21.     <property name="Yeast"/>
  22.     <property name="BatchSize"/>
  23.     <property name="Note"/>
  24.     <!– nhibernate will set up a foreign key relationship between tables for us –>
  25.     <bag name="IngredientsUsed" cascade="all" lazy="true">
  26.       <key column="RecipeID"/>
  27.       <one-to-many class="Ingredient"/>
  28.     </bag>
  29.    
  30.     <!– lazy = true is default, don’t necessarily need it–>
  31.     <bag name="RecipeImpressions" cascade="all">
  32.       <key column="RecipeID"/>
  33.       <one-to-many class="Impression"/>
  34.     </bag>
  35.  
  36.     <many-to-one name="Brewer" column="Brewer" class="Person"/>
  37.  
  38.   </class>
  39. </hibernate-mapping>

The first item of interest here is the “hibernate-mapping” tag. This obviously is responsible for identifying the file as an NHibernate mapping file. Its’ also handy to be able to define the assembly and namespace in this tag as well. This is similar to a “using” directive in C# code, in that you won’t need to specify the assembly or namespace for each class you define.

After this, the class definitions are fairly straightforward. It is important to note that we need to specify the table that each class maps to however. In this example we are not specifying the data width for any of our columns of type “string” after the first one. This is because we will be relying on NHibernate to create our schema.

Its’ also important to note that we need to define an Id column for each type. While we won’t really be using this in our programming, NHibernate needs it to keep track of objects, and manage the relationships.

Finally, we get down to where the mappings are established. As we saw in the domain diagram in part 1, each recipe is related to three other types in the application. A recipe can have any number of Ingredients, any number of Impressions, and one brewer (of type Person). The first two relationships need to be defined as one to many, and the third as a many to one (because one brewer could have any number of recipes). We used a “bag” because this corresponds to an IList. You can also use “set” which corresponds to an IEnumerable.

Now, we have defined our domain, and thus our database schema. Next part is to set up our first unit test, to ensure that NHibernate can create the schema we’ve defined.

Need help with C#? Come and ask a question in our C# Forum

Leave a comment »Send a trackback » 507 views

:: Next >>