Angel \”Java\” Lopez on Blog

October 7, 2011

The Repository Pattern: Links, News and Resources (1)

These are my links about Repository Pattern: the differences with DAOs (Data Access Objects); examples with NHibernate, Entity Framework; its use in DDD; its relation to IUnitOfWork; discussion about how to query a repository; the influence of Linq/IQueriable in the evolution of this pattern in .NET (LINQ/IQueryable is a missing piece in Java). There are interesting discussions in Spanish, too. I recommend you should translate them.

Repository
http://martinfowler.com/eaaCatalog/repository.html

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. Client objects construct query specifications declaratively and submit them to Repository for satisfaction. Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.

LLBLGenPro, Entity Framework 4.1, and the Repository Pattern
http://www.mattjcowan.com/funcoding/2011/09/25/llblgen-ef-repository-pattern/

HunabKu: LINQ and Repository
http://fabiomaulo.blogspot.com/2009/06/linq-and-repository.html

Revisiting the Repository and Unit of Work Patterns with Entity Framework
http://blogs.microsoft.co.il/blogs/gilf/archive/2010/06/21/revisiting-the-repository-and-unit-of-work-patterns-with-entity-framework.aspx

EFMVC
http://efmvc.codeplex.com/
Demo web app using ASP.NET MVC 3 RTM, Razor, EF Code First and Unity 2.0
Repository Pattern and Unit of Work

Repository is Dead: Long Live Repository
http://codebetter.com/gregyoung/2009/04/23/repository-is-dead-long-live-repository/

Repository is the new Singleton
http://ayende.com/blog/3955/repository-is-the-new-singleton

DDD: The Generic Repository
http://codebetter.com/gregyoung/2009/01/16/ddd-the-generic-repository/

The Repository Pattern
http://blogs.hibernatingrhinos.com/nhibernate/archive/0001/01/01/the-repository-pattern.aspx

N-Tiers using POCOs and Entity Framework – Part Two: Model and Entities
http://blog.jorgef.net/2010/09/n-tiers-pocos-ef-2.html

N-Tiers using POCOs and Entity Framework – Part Five: DataAccess Layer
http://blog.jorgef.net/2010/09/n-tiers-pocos-ef-5.html

N-Tiers using POCOs and Entity Framework – Part Six: Source Code
http://blog.jorgef.net/2011/02/n-tiers-pocos-ef-6.html

Using the NHibernate Repository Pattern in C# ASP .NET
http://jasper-net.blogspot.com/2011/04/using-nhibernate-repository-pattern-in.html

Mock a database repository using Moq
http://www.codeproject.com/Articles/47603/Mock-a-database-repository-using-Moq.aspx

The wages of sin: Proper and improper usage of abstracting an OR/M
http://ayende.com/blog/4788/the-wages-of-sin-proper-and-improper-usage-of-abstracting-an-or-m

The wages of sin: Over architecture in the real world
http://ayende.com/blog/4786/the-wages-of-sin-over-architecture-in-the-real-world

Architecting in the pit of doom: The evils of the repository abstraction layer
http://ayende.com/blog/4784/architecting-in-the-pit-of-doom-the-evils-of-the-repository-abstraction-layer
Better Domain-Driven Design Implementation
http://www.udidahan.com/2007/03/06/better-domain-driven-design-implementation/

Entities, Services and what goes between them…
http://ayende.com/blog/2145/entities-services-and-what-goes-between-them

Suteki Shop
http://mikehadlow.blogspot.com/search/label/Suteki%20Shop
http://code.google.com/p/sutekishop/
Suteki Shop is an eCommerce application. The orginal aim is to write a site for a fashion retail business. It includes a product catalogue, shopping cart and order processing.
Using
    * .NET 4.0
    * ASP.NET MVC 3
    * MVC Contrib
    * NHibernate
    * Windsor IoC Container

Hunabku
https://bitbucket.org/fabiomaulo/hunabku
Source for @fabiomaulo blog examples
http://www.fabiomaulo.blogspot.com/

Repository, IQueryable y otras hierbas
http://cprieto.com/index.php/2010/05/20/repository-iqueryablet-y-otras-hierbas/
"cuando Fowler y Eric Evans en su libro DDD definieron Repository no existía el concepto de IQueryable y creo que no muchos se lo veían venir, así que simplemente si asociamos que Repository es una abstración superior del acceso a datos y este se debe comportar como una colección en memoria (mezclando las definiciones de Fowler y Evans) y coincidimos en que en la .Net Framework las colecciones pueden extenderse a IQueryable, es fácil razonar que por definición un repositorio finaliza implementando IQueryable<T> (mera jalada mi filosofía y asociación, pero para filósofo preguntémosle mejor a @ajlopez!)" <—Great! @cprieto reads my philosophy posts 😉
Spanish discussion http://groups.google.com/group/altnet-hispano/browse_thread/thread/9c9e84a850dd00bc

HunabKu: Enhanced Query Object
http://fabiomaulo.blogspot.com/2010/07/enhanced-query-object.html

Implementing Repository Pattern With Entity Framework
http://www.codeproject.com/KB/database/ImplRepositoryPatternEF.aspx

Entity Framework as Repository and UnitOfWork?
http://stackoverflow.com/questions/520065/entity-framework-as-repository-and-unitofwork

Repository or DAO?: Repository
http://fabiomaulo.blogspot.com/2009/09/repository-or-dao-repository.html

Repository or DAO?: DAO
http://fabiomaulo.blogspot.com/2009/09/repository-or-dao-dao.html

Repositories for Value Objects?
http://tech.groups.yahoo.com/group/domaindrivendesign/message/17972

How to use dependency injection and the repository pattern with ASP.NET web services?
http://stackoverflow.com/questions/1449870/how-to-use-dependency-injection-and-the-repository-pattern-with-asp-net-web-servi

FubuMVC Contrib
http://code.google.com/p/fubumvc-contrib/
Contrib for FubuMVC a Front Controller-style MVC framework designed primarily for Web applications built on ASP.NET
Many samples with IRepository, NHibernate, IUnitOfWork

MPBlog Implementation. Part 4
http://www.simplyvinay.com/Post/50/MPBlog-Implementation.-Part-4.aspx
NHibernate Repository and Unit Of Work

Linq specifications: from Argentina with Love
http://joseoncode.com/2009/12/24/linq-specifications-from-argentina-with-love/

IRepository interface
http://weblogs.asp.net/alexeyzakharov/archive/2009/11/18/irepository-interface.aspx

nHibernate, Linq and Queries
http://lucisferre.net/2009/05/19/nhibernate-linq-and-queries/

The DAL should go all the way to UI
http://ayende.com/blog/3958/the-dal-should-go-all-the-way-to-ui

Returning IQueryable<T>
http://weblogs.asp.net/fredriknormen/archive/2008/12/01/returning-iqueryable-lt-t-gt.aspx

Generic Repository
http://grepo.codehaus.org/
The Generic Repository (grepo) is an open source (ASLv2) framework for Java which allows you to access (database) repositories in a generic and consistent manner.

The catalogue metaphor and command-query seperation architectures
http://codebetter.com/iancooper/2009/10/08/the-catalogue-metaphor-and-command-query-seperation-architectures/
Query Objects vs Methods on a Repository
http://www.udidahan.com/2007/03/28/query-objects-vs-methods-on-a-repository/

Using Repository and Unit of Work patterns with Entity Framework 4.0
http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit-of-work-patterns-with-entity-framework-4-0.aspx

AltNet-Argentina: DAO, Repository y clases Query
http://groups.google.com/group/altnet-argentina/browse_thread/thread/a3f5324ab8418277?pli=1

DDD: The Generic Repository
http://codebetter.com/gregyoung/2009/01/16/ddd-the-generic-repository/

My Links
http://www.delicious.com/ajlopez/repository

More links about other patterns are coming.

Keep tuned!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

May 28, 2011

NHibernate 3 (Part 7) One-To-Many with Inverse

Filed under: .NET, C Sharp, NHibernate — ajlopez @ 11:40 am

Previous Post
Next Post

The previous example had a problem: it use one INSERT AND one UPDATE for each chapter. In this post, I use an alternative way to mapping a one-to-many list, using the inverse attribute. As usual, the code is at my AjCodeKata Code Project, under trunk/NHibernate/BookChapters. You can download a “frozen” version from NHibernate3BookChaptersInverse.zip.

I modified the previous solution, adding a new Books.Inverse console project, copying the original Books.Console. And I added a new attribute in Book mapping:

<list name="Chapters" cascade="all-delete-orphan" 
  inverse="true">
  <key column="BookId"/>
  <index column="ChapterIndex"/>
  <one-to-many class="Chapter"/>
</list>

The new attribute is inverse=”true”. With this clue, NHibernate knows that the management of the list and its items are under programmer control. What does it mean? I ran the new console program: each chapter is saved with only ONE insert, but the result in the database was:

No BookId, no ChapterIndex were set! The problem is in the code:

cookbook.Chapters.Add(new Chapter() { Title = "Models and Mappings" });
cookbook.Chapters.Add(new Chapter() { Title = "Configuration and Schema" });
cookbook.Chapters.Add(new Chapter() { Title = "Sessions and Transactions" });

When I created a new Chapter, I didn’t set any Book or Chapter Index information. With inverse=”true”, now that is my responsibility. Then, I changed the Chapter class, adding a new property:

// Used in Inverse example
public virtual int ChapterIndex { get; set; }

And I changed the chapter creation code to:

cookbook.Chapters.Add(new Chapter() { Title = "Models and Mappings", Book = cookbook, ChapterIndex = 0 });
cookbook.Chapters.Add(new Chapter() { Title = "Configuration and Schema", Book = cookbook, ChapterIndex = 1 });
cookbook.Chapters.Add(new Chapter() { Title = "Sessions and Transactions", Book = cookbook, ChapterIndex = 2 });

Now, the output of the insert is:

NHibernate: INSERT INTO Books (Title, Author, Id) VALUES (@p0, @p1, @p2);@p0 = 
'NHibernate Cookbook' [Type: String (4000)], @p1 = 'Jason Dentler' 
[Type: String (4000)], @p2 = b643aa0e-1917-4066-96a4-64a09562a58a [Type: Guid (0)]

NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Models and Mappings' [Type: String (4000)], @p1 
 = NULL [Type: String (4000)], @p2 = b643aa0e-1917-4066-96a4-64a09562a58a
 [Type : Guid (0)], @p3 = 0 [Type: Int32 (0)], @p4 = 
 df9114af-7183-4b1b-9826-d12982a898a5 [Type: Guid (0)]
 
NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Configuration and Schema' 
 [Type: String (4000)], @p1 = NULL [Type: String (4000)], @p2 =
 b643aa0e-1917-4066-96a4-64a09562a58a [Type: Guid (0)], @p3 = 1 [Type: Int32 (0)],
 @p4 = 3fc1df36-c7de-4ff8-add2-8f843b627115 [Type: Guid (0)]

NHibernate: INSERT INTO Chapters (Title, Notes, BookId, ChapterIndex, Id) VALUES
 (@p0, @p1, @p2, @p3, @p4);@p0 = 'Sessions and Transactions' 
 [Type: String (4000)], @p1 = NULL [Type: String (4000)], @p2 = 
 b643aa0e-1917-4066-96a4-64a09562a58a  [Type: Guid (0)], @p3 = 2 [Type: Int32 (0)],
 @p4 = 9c8891e4-6419-4469-aa3a-154f2c908985 [Type: Guid (0)]

Chapters are saved as:

All Ok! Note that I have not to add the chapters to the NHibernate session: they are saved as part of the saved book. But after inverse=true, I should set the inverse relation (Chapter to Book) and order properties.

Next steps: explore deletion, update, more complex mapping, logging options, alternative mappings (Fluent NHibernate, ConfORM, new NHibernate 3.2 mapping by code).

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

May 19, 2011

NHibernate 3 (Part 6) One-To-Many with Many-To-One

Filed under: .NET, C Sharp, NHibernate — ajlopez @ 11:11 am

Previous post
Next post

The database is the same from the previous example (the same name and scripts):

But now, I want to have a reference, in the domain, from chapter to book:

public class Chapter
{
    public virtual Guid Id { get; set; }
    public virtual string Title { get; set; }
    public virtual string Notes { get; set; }
	
	// New property
    public virtual Book Book { get; set; } 
}

So, I changed the Chapter mapping to:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Books"
namespace="Books">
  <class name="Chapter" table="Chapters">
    <id name="Id">
      <generator class="guid" />
    </id>
    <property name="Title" not-null="true" />
    <property name="Notes" />
    <many-to-one name="Book" column="BookId" />
  </class>
</hibernate-mapping>

The new element is many-to-one. The Book mapping has no change:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Books"
namespace="Books">
  <class name="Book" table="Books">
    <id name="Id">
      <generator class="guid" />
    </id>
    <property name="Title" not-null="true" />
    <property name="Author" not-null="true"/>
    <list name="Chapters" cascade="all-delete-orphan">
      <key column="BookId"/>
      <index column="ChapterIndex"/>
      <one-to-many class="Chapter"/>
    </list>
  </class>
</hibernate-mapping>

I added the “show_sql” in the configuration file, NHibernate section:

  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.connection_string">Data Source=.\SQLEXPRESS;Initial Catalog=NHibernate3BooksOneToMany;Integrated Security=True</property>
      <property name="proxyfactory.factory_class">
        NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle
      </property>
     <property name="show_sql">true</property>
      <mapping assembly="Books.Console" />
    </session-factory>
  </hibernate-configuration>

This property is very useful when you are learning about NHibernate: it dumps in console the SQL commands that NHibernate executes during its operation. This is the main console program:

ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
using (ISession session = sessionFactory.OpenSession())
{
    using (ITransaction tx = session.BeginTransaction())
    {
        Book cookbook = new Book()
        {
            Title = "NHibernate Cookbook",
            Author = "Jason Dentler",
            Chapters = new List<Chapter>()
        };
        cookbook.Chapters.Add(new Chapter() { Title = "Models and Mappings" });
        cookbook.Chapters.Add(new Chapter() { Title = "Configuration and Schema" });
        cookbook.Chapters.Add(new Chapter() { Title = "Sessions and Transactions" });
        session.Save(cookbook);
        tx.Commit();
        session.Close();
    }
}
using (ISession session = sessionFactory.OpenSession())
{
    foreach (Book book in session.Query<Book>().Fetch(b => b.Chapters))
        {
            System.Console.WriteLine(string.Format("Book {0}", book.Title));
            int nchapter = 0;
            foreach (Chapter chapter in book.Chapters)
            {
                System.Console.WriteLine(string.Format("Chapter {0}:{1}", ++nchapter, chapter.Title));
                System.Console.WriteLine(string.Format("From Book {0}", chapter.Book.Title));
            }
        }
}
System.Console.ReadKey();

A new method is invoke: .Fetch. I’ll explain it below. Now, run the program, and examine the console output. First:

NHibernate: INSERT INTO Books (Title, Author,
 Id) VALUES (@p0, @p1, @p2);@p0 = 'NHibernate Cookbook' [Type: String (4000)], @p1 = 
'Jason Dentler' [Type: String (4000)], 
@p2 = 20d05308-aea1-49f2-9b4a-7441e73dab4e [Type: Guid (0)]

This is the command that inserts the new book. Then:

NHibernate: INSERT INTO Chapters (Title, Notes, BookId, Id) VALUES (@p0, @p1, @p 
2, @p3);@p0 = 'Models and Mappings' [Type: String (4000)], @p1 = NULL [Type: 
String (4000)], @p2 = NULL [Type: Guid (0)], @p3 = 
15ce4169-08ef-4f75-8493-8fe68da7e918 [Type: Guid (0)] 
NHibernate: INSERT INTO Chapters (Title, Notes, BookId, Id) VALUES (@p0, @p1, @p2, @p3);
@p0 = 'Configuration and Schema' [Type: String (4000)], @p1 = NULL [Type: String (4000)],
 @p2 = NULL [Type: Guid (0)], @p3 = 3edb510d-4cbd-44fd-b4a1-094a258ec07f [Type: Guid (0)] 
NHibernate: INSERT INTO Chapters (Title, Notes, BookId, Id) VALUES (@p0, @p1, @p2,
 @p3);@p0 = 'Sessions and Transactions' [Type: String (4000)], @p1 = NULL [Type: String (4000)], @p2 = NULL [Type: Guid (0)], @p3 = af025d1b-cdc6-4c8f-9014-71c5dee135e1 [Type: Guid (0)]

These commands insert the three chapters. Hey! They ARE NOT setting the BookId (note @p2 = NULL) and no mention of ChapterIndex. Curiously, NHibernate set those columns IN A SECOND PASS:

NHibernate: UPDATE Chapters SET BookId = @p0, ChapterIndex = @p1 WHERE Id = @p2; 
@p0 = 20d05308-aea1-49f2-9b4a-7441e73dab4e [Type: Guid (0)], @p1 = 0 [Type: 
Int32 (0)], @p2 = 15ce4169-08ef-4f75-8493-8fe68da7e918 [Type: Guid (0)] 
NHibernate: UPDATE Chapters SET BookId = @p0, ChapterIndex = @p1 WHERE Id = @p2; 
@p0 = 20d05308-aea1-49f2-9b4a-7441e73dab4e [Type: Guid (0)], @p1 = 1 [Type: 
Int32 (0)], @p2 = 3edb510d-4cbd-44fd-b4a1-094a258ec07f [Type: Guid (0)] 
NHibernate: UPDATE Chapters SET BookId = @p0, ChapterIndex = @p1 WHERE Id = @p2; 
@p0 = 20d05308-aea1-49f2-9b4a-7441e73dab4e [Type: Guid (0)], @p1 = 2 [Type: 
Int32 (0)], @p2 = af025d1b-cdc6-4c8f-9014-71c5dee135e1 [Type: Guid (0)]

This is weird (and it’s the reason why we have to define ChapterIndex and BookId as nullable, as I mentioned in the previous example). I would expect NHibernate save in one pass the Book+Chapters. I don’t know why it is the “natural” behavior, and is one of the many behaviors we have to learn in order to master NHibernate. Note that usefulness of show_sql: there are other options to log NHibernate (notable, log4net logging), but this is a simple property you can use now in your initial programs. We should improve this behavior in an upcoming post.

This is the select statement:

NHibernate: select book0_.Id as Id0_0_, chapters1_.Id as Id1_1_, book0_.Title as 
Title0_0_, book0_.Author as Author0_0_, chapters1_.Title as Title1_1_, chapters 
1_.Notes as Notes1_1_, chapters1_.BookId as BookId1_1_, chapters1_.BookId as Boo 
kId0__, chapters1_.Id as Id0__, chapters1_.ChapterIndex as ChapterI5_0__ from Bo 
oks book0_ left outer join Chapters chapters1_ on book0_.Id=chapters1_.BookId

Surprise: The select retrieves Books AND Chapters, using an outer join. In this way, NHibernate can fill the chapters of each book. But this behavior is not the “default” one: the chapters are not loaded every time you retrieves a book. The NHibernate default behavior is to load the Chapters list ONLY when you iterate over it. If you don’t use the list, the chapters are not loaded. The above statement (and the adding of the join) is a consequence of using the Fetch:

foreach (Book book in session.Query<Book>().Fetch(b => b.Chapters))

That additional method says: “Hey, NHibernate! Go and get the book, but the chapters too!”. You can experiment, and remove the Fetch method. Then, this is the partial output (another data set):

NHibernate: select book0_.Id as Id0_, book0_.Title as Title0_, book0_.Author as 
Author0_ from Books book0_ 
Book NHibernate Cookbook 
NHibernate: SELECT chapters0_.BookId as BookId1_, chapters0_.Id as Id1_, chapter 
s0_.ChapterIndex as ChapterI5_1_, chapters0_.Id as Id1_0_, chapters0_.Title as Title1_0_,
 chapters0_.Notes as Notes1_0_, chapters0_.BookId as BookId1_0_ FROM Chapters
 chapters0_ WHERE chapters0_.BookId=@p0;@p0 = 
cfb043eb-6ffc-4727-a5ad-05afe867ab57 [Type: Guid (0)] 
Chapter 1:Models and Mappings 
From Book NHibernate Cookbook 
Chapter 2:Configuration and Schema 
From Book NHibernate Cookbook 
Chapter 3:Sessions and Transactions 
From Book NHibernate Cookbook

There is a select for the book, and then, FOR EACH BOOK (trust me 😉 there is a new select for its chapter. Again: another “behavior” to have into account in order to have a program that doesn’t abuse of database commands. Note that the output:

Book NHibernate Cookbook

PRECEDES the select of the chapters. Until the program iterates the chapter list, NO SELECT is performed. Another point: chapter.Book is not null. Thanks to NHibernate, the reference from Chapter to its parent Book is automatically filled.

So, this is the reason for the added .Fetch method. We have to explore alternatives to circumvent the pair INSERT-UPDATE for each chapter, topic for the next post.

As usual, the code is at my AjCodeKata Code Project, under trunk/NHibernate/BookChapters. You can download a “frozen” version from NHibernate3BookChapters.zip.

Next steps: explore inverse=”true”, other logging options, many-to-many, session cache, etc.

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

May 9, 2011

NHibernate 3 (Part 5) First One-To-Many Mapping

Filed under: .NET, C Sharp, NHibernate — ajlopez @ 9:57 am

Previous post
Next post

This time, I want to map this data model:

Each book can have zero, one or more chapters. This is the class diagram for my domain:

This is the code for Book.cs:

public class Book
{
    public virtual Guid Id { get; set; }
    public virtual string Title { get; set; }
    public virtual string Author { get; set; }
    public virtual IList<Chapter> Chapters { get; set; }
}

As usual, the properties are virtual (I should write why, in upcoming post). And note, Chapters is a IList<Chapter>. The IList will be loaded by NHibernate. The Chapter.cs class:

public class Chapter
{
    public virtual Guid Id { get; set; }
    public virtual string Title { get; set; }
    public virtual string Notes { get; set; }
}

The book mapping has a new element:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Books"
namespace="Books">
  <class name="Book" table="Books">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="Title" not-null="true" />
    <property name="Author" not-null="true"/>
    <list name="Chapters" cascade="all-delete-orphan">
      <key column="BookId"/>
      <index column="ChapterIndex"/>
      <one-to-many class="Chapter"/>
    </list>
  </class>
</hibernate-mapping>

The <list> element points to the Book property Chapters. The elements will be ordered based on the table column ChapterIndex. BookId and ChapterIndex are not properties in Chapter class. They are columns in Chapter table. The Chapter mapping has no reference to Book class:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Books"
namespace="Books">
  <class name="Chapter" table="Chapters">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="Title" not-null="true" />
    <property name="Notes" />
  </class>
</hibernate-mapping>

What does the “cascade=all-delete-orphan” attribute mean? You have more info at:

http://www.nhforge.org/doc/nh/en/index.html#collections-onetomany

The programmer can add and remove chapters from/to a book object, and NHibernate will take care of their persistence. If an object is removed from the list via code, NHibernate will delete the removed chapter IF it has not added to OTHER book. It would be an “orphan” chapter.

This is the code to add and retrieve a book with chapters:

ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
using (ISession session = sessionFactory.OpenSession())
{
    using (ITransaction tx = session.BeginTransaction())
    {
        Book cookbook = new Book()
        {
            Title = "NHibernate Cookbook",
            Author = "Jason Dentler",
            Chapters = new List<Chapter>() { 
                new Chapter() { Title = "Models and Mappings" },
                new Chapter() { Title = "Configuration and Schema" },
                new Chapter() { Title = "Sessions and Transactions" }
            }
        };
        session.Save(cookbook);
        foreach (Book book in session.Query<Book>())
        {
            System.Console.WriteLine(string.Format("Book {0}", book.Title));
            int nchapter = 0;
            foreach (Chapter chapter in book.Chapters)
                System.Console.WriteLine(string.Format("Chapter {0}:{1}", ++nchapter, chapter.Title));
        }
        tx.Commit();
        session.Close();
    }
}

I had a problem: initially, I defined ChapterIndex and BookId as not-null in Chapter table. But, notably, NHibernate requires that those fields could accept null values. So, in my first attempts, I got an error when I save a new book. Then, I read the note (from the above link in NHForge documentation):

Very Important Note: If the <key> column of a <one-to-many> association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter.

I changed the columns to nullable, and all worked OK. I’m still puzzle by this requirement: I expected that NHibernate filled the BookId and ChapterIndex DURING the saving of each chapter. But not. It saved the chapter with those fields with null, and THEN, it updated the row.

The code of this post, as usual, is in my AjCodeKatas Google Project, under trunk/NHibernate/BooksOneToMany. You can download a “current frozen” version from NHibernate3BooksOneToMany.zip.

Next steps: explore more one-to-many options, bidirectional mappings, and more.

My sources of information: book: Jason Dentler’s NHibernate 3.0 Cookbook

http://ayende.com/Blog/archive/2006/12/02/nhibernatecascadesthedifferentbetweenallalldeleteorphansandsaveupdate.aspx

http://www.nhforge.org/doc/nh/en/index.html#collections-onetomany

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

April 12, 2011

NHibernate 3 (Part 4) Table Per Class

Filed under: .NET, C Sharp, NHibernate — ajlopez @ 10:50 am

Previous post
Next post

In the previous posts (Table per Hierarchy, Table Per Concrete Class), I implemented two mapping strategies for the same model:

Now, I want to map EACH class to a table:

The solution has two projects, one console project, and the other is a class library:

You can download the code from NHibernate3ItemsTablePerClass.zip. You need to add NHibernate libraries (see a previous post for more details). The database can be created running ExecuteAll.cmd at Sql folder. The command accepts a parameter (e.g. ExecuteAll (local)) as the database server. The default value is .\SQLEXPRESS.

The Item mapping:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerClass.Domain"
namespace="ItemsTablePerClass.Domain">
  <class name="Item" table="Items">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="Title" not-null="true" />
    <property name="Description" not-null="true" />
  </class>
</hibernate-mapping>

There is a table attribute, and no discriminator value. The new “thing” is at Note mapping:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerClass.Domain"
namespace="ItemsTablePerClass.Domain">
  <joined-subclass name="Note" extends="Item" table="Notes">
    <key column="Id" />
    <property name="Content" />
  </joined-subclass>
</hibernate-mapping>

The new element is joined-subclass. There is a table attribute for this mapping too. And no id element. It was replaces by the key element that joins both tables.

Similar changes at Page mapping:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerClass.Domain"
namespace="ItemsTablePerClass.Domain">
  <joined-subclass name="Page" extends="Item" table="Pages">
    <key column="Id" />
    <property name="Url"/>
  </joined-subclass>
</hibernate-mapping>

Notably, the main code is the same as in the previous examples. And the domain classes are still untouched.

Next steps: start to research one-to-many mappings, other alternatives to mapping (Fluent NHibernate, ConfORM, new NHibernate 3.2 API).

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

April 11, 2011

NHibernate 3 (Part 3) Table Per Concrete Class

Filed under: .NET, C Sharp, NHibernate — ajlopez @ 9:49 am

Previous post
Next post

I want to use the same domain from the previous post:

 

but this time, I want two tables: one for Notes, another for Pages:

The solution has two projects: a class library containing the domain, and the console project:

The code is at my AjCodeKatas Google code project, under trunk/NHibernate/ItemsTablePerConcreteClass. The code doesn’t include the NHibernate libraries, so you must add the references to the solution. As in the previous example, I added as reference to console project: NHibernate.dll from the NHibernate folder Required_Bins and NHibernate.ByteCode.Castle from Required_For_LazyLoading\Castle. I added the .xsd files (XML schemas to support intellisense when writing the mapping files) from NHibernate folde Required_Bins.

You can download the source code directly from NHibernate3ItemsTablePerConcreteClass.zip. If you need the NHibernate 3.x libraries, check http://nhforge.org or download my first example NHibernate3SimpleMapping.zip, that includes them. Check my first post to review: libraries to add, schemas, configuration file, and mapping files (don’t forget to add as embedded resources).

Note that the domain classes are the same: they don’t change from the previous example. I changed the mapping files, not the code. This is a proof of domain independence of our mapping strategy.

First, the Item.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerConcreteClass.Domain"
namespace="ItemsTablePerConcreteClass.Domain">
  <class name="Item" abstract="true">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="Title" not-null="true" />
    <property name="Description" not-null="true" />
  </class>
</hibernate-mapping>

First, I removed the discriminator column. There is no such column, because there is no Items table. I added the attribute abstract=”true”. If you forget to add it, then NHibernate “thinks” you have a concrete table for this class. You can remove it, if you have concrete Items that are not Notes, Pages. This is not the case I want to implement: the only “real” items are Notes or Pages. Item is an abstraction in my domain.

The Note.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerConcreteClass.Domain"
namespace="ItemsTablePerConcreteClass.Domain">
  <union-subclass name="Note" extends="Item" table="Notes">
    <property name="Content" />
  </union-subclass>
</hibernate-mapping>

I added the attribute table=”Notes”. And the new element is union-subclass, instead of subclass as in previous example. This new element is the way to say: “the table of this class CONTAINS the columns to save the parent class values”. That is: the table columns are the UNION of the parent class and this class values.

Similar changes for Page.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerConcreteClass.Domain"
namespace="ItemsTablePerConcreteClass.Domain">
  <union-subclass name="Page" extends="Item" table="Pages">
    <property name="Url"/>
  </union-subclass>
</hibernate-mapping>

The main code is practical the same from the previous example:

ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
using (ISession session = sessionFactory.OpenSession())
{
    using (ITransaction tx = session.BeginTransaction())
    {
        Page page1 = new Page();
        page1.Title = "Technical Blob";
        page1.Description = "My Personal Technical Blob in English";
        page1.Url = "https://ajlopez.wordpress.com";
        Page page2 = new Page();
        page2.Title = "My Personal Blob";
        page2.Description = "My Personal Blob in Spanish";
        page2.Url = "http://ajlopez.zoomblog.com";
        Note note1 = new Note();
        note1.Title = "To Do";
        note1.Description = "My To Do List";
        note1.Content = "Practice NHibernate";
        session.Save(page1);
        session.Save(page2);
        session.Save(note1);
        var items = session.Query<Item>(); ;
        foreach (Item item in items)
            System.Console.WriteLine(string.Format("Item {0}", item.Title));
        tx.Commit();
        session.Close();
    }
}

except that this time, I began to use Session.Query<T>, a new extension method for NHibernate sessions, that returns a IQueryable<T> implementing Linq. You MUST add:

using NHibernate.Linq;

to have this method. It is an extension method, not a “natural one” for ISession.

My sources of information:

Book: Jason Dentler’s NHibernate 3.0 Cookbook

http://www.nhforge.org/doc/nh/en/index.html#mapping-declaration-unionsubclass

http://www.nhforge.org/doc/nh/en/index.html#inheritance

Next steps: implement Table per Class strategy, explore one-to-many, lazy collections, etc.Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

April 5, 2011

NHibernate 3 (Part 2) Table per Hierarchy

Filed under: .NET, C Sharp, NHibernate — ajlopez @ 9:18 am

Previous post
Next post

In the previous post of this series, I implemented a simple mapping: one class, one table.

But now, I have three classes, with inheritance:

The Id is a System.Guid. I want to have an item collection. Each item can be a Note, with text content, or a web Page, with an associated URL. The solution has two projects:

I keep the source code at my AjCodeKatas Google code project, under trunk/NHibernate/ItemsTablePerHierarchyMapping. The code doesn’t include the NHibernate libraries, so you must add the references to the solution. I added as reference to console project: NHibernate.dll from the NHibernate folder Required_Bins and NHibernate.ByteCode.Castle from Required_For_LazyLoading\Castle.

If you are lazy, like me, and you want a ready-to-build solution, you can download the previous example with NHibernate required files from my Skydrive: NHibernate3SimpleMapping.zip. The code of this post is at: NHibernate3ItemsTablePerHierarchy.zip.

The Domain project has no reference to NHibernate. All the mappings are in the Console project, as embedded resource (don’t forget this).

I have 3 classes to map. But I want to store all data in only one table:

You can generate the database executing ExecuteAll.cmd in Sql directory.

The table Items has a column ItemType, that mark an item as a Note or as a Page. The Item.hbm.xml reference that column as a discriminator:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerHierarchyMapping.Domain"
namespace="ItemsTablePerHierarchyMapping.Domain">
  <class name="Item" table="Items">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <discriminator column="ItemType" />
    <property name="Title" not-null="true" />
    <property name="Description" not-null="true" />
  </class>
</hibernate-mapping>

Note that I have no such property in the classes: the discriminator is only used by NHibernate.

Now, I need to map Note objects. How to write the mapping? This is Note.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerHierarchyMapping.Domain"
namespace="ItemsTablePerHierarchyMapping.Domain">
  <subclass name="Note" extends="Item" discriminator-value="Note">
    <property name="Content" />
  </subclass>
</hibernate-mapping>

The new XML element is subclass. It has an extends attribute that reference to the parent class. The discriminator-value attribute has the value to put in the discriminator column when the Item is a Note. If you don’t specify the discriminator value, the name of the class would be used, in this case ItemsTablePerHierarchyMappin.Domain.Note.

The Page.hbm.xml is similar:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ItemsTablePerHierarchyMapping.Domain"
namespace="ItemsTablePerHierarchyMapping.Domain">
  <subclass name="Page" extends="Item" discriminator-value="Page">
    <property name="Url"/>
  </subclass>
</hibernate-mapping>

You can run the console code:

ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
using (ISession session = sessionFactory.OpenSession())
{
    using (ITransaction tx = session.BeginTransaction())
    {
        Page page1 = new Page();
        page1.Title = "Technical Blob";
        page1.Description = "My Personal Technical Blob in English";
        page1.Url = "https://ajlopez.wordpress.com";
        Page page2 = new Page();
        page2.Title = "My Personal Blob";
        page2.Description = "My Personal Blob in Spanish";
        page2.Url = "http://ajlopez.zoomblog.com";
        Note note1 = new Note();
        note1.Title = "To Do";
        note1.Description = "My To Do List";
        note1.Content = "Practice NHibernate";
        session.Save(page1);
        session.Save(page2);
        session.Save(note1);
        IQuery query = session.CreateQuery("from Item");
        foreach (Item item in query.List<Item>())
			System.Console.WriteLine(string.Format("Item {0}", item.Title));
        tx.Commit();
        session.Close();
    }
}
System.Console.ReadKey();

to insert and list items.

This mapping strategy (the old trick of saving every subclass in a single table, using discriminators 😉 is called Table Per Hierarchy (Fowler names it Single Table Inheritance).

Next steps: implement other mapping strategies: one table per concrete class (in this case, Pages and Notes); one table per class (Items, Pages, Notes).

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

January 17, 2011

NHibernate 3 (Part 1) Simple Mapping

Filed under: .NET, C Sharp, NHibernate — ajlopez @ 9:27 am

Next post

Year and half ago I wrote an example:

First NHibernate 2.x Example

This year, I want to explore the new release: NHibernate 3.0. You can download the current version from:

http://sourceforge.net/projects/nhibernate/files/

I get NHibernate-3.0.0.GA-bin.zip to use in this solution:

I keep the source code at my AjCodeKatas Google code project, under trunk/NHibernate/SimpleMapping. The code doesn’t include the NHibernate libraries, so you must add the references to the solution. I added all libraries from the NHibernate folders Required_Bins and Required_For_LazyLoading\Castle.

If you are lazy, like me, and you want a ready-to-build solution, you can download the complete example with NHibernate required files from my Skydrive: NHibernate3SimpleMapping.zip.

Note that I created a solution folder Schemas, and add the .xsd files I found at NHibernate distribution in Required_Bins folder.

The SimpleMapping.Domain contains only a class:

    public class Customer
    {
        public virtual Guid Id { get; set; }
        public virtual string Name { get; set; }
        public virtual string Address { get; set; }
        public virtual string Notes { get; set; }
    }

This class library has no reference to NHibernate. I wrote an app.config file for the console application:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section
    name="hibernate-configuration"
    type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
/>
  </configSections>
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.connection_string">Data Source=.\SQLEXPRESS;Initial Catalog=NHibernate3SimpleMapping;Integrated Security=True</property>
      <property name="proxyfactory.factory_class">
        NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle
      </property>
      <mapping assembly="SimpleMapping.Console" />
    </session-factory>
  </hibernate-configuration>
</configuration>

I wrote a Customer.hbm.xml file and mark it as Embedded Resources in his properties window (don’t forget this step: this is the way the example uses to tell NHibernate what classes to map):

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="SimpleMapping.Domain"
namespace="SimpleMapping.Domain">
  <class name="Customer" table="Customers">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="Name" not-null="true" />
    <property name="Address" />
    <property name="Notes" />
  </class>
</hibernate-mapping>

To create the database, run Sql\ExecuteAll.cmd (see Readme.txt for more details).

The console program only creates a customer, save it in the database, and retrieve all existing customer:

    ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
    using (ISession session = sessionFactory.OpenSession())
    {
        using (ITransaction tx = session.BeginTransaction())
        {
            Customer customer1 = new Customer();
            customer1.Name = "Customer 1";
            customer1.Address = "Address 1";
            customer1.Notes = "Notes 1";
            session.Save(customer1);
            IQuery query = session.CreateQuery("from Customer");
    
            foreach (Customer c in query.List<Customer>())
                System.Console.WriteLine(string.Format("Customer {0}", c.Name));
            tx.Commit();
            session.Close();
        }
    }

(Sorry, I’m not very creative in the values of the properties 😉

There are many details to discuss: Why Castle bytecode? what does each property in configuration mean? What is a session? An  a transaction? What is an Id? What is a guid.comb? Options instead of guid.comb? How to map other kind of properties (currency values? dates?).

And what if we need more classes? Inheritance mapping? One to many? Lot of stuff to explore in upcoming posts.

Meanwhile, some resources:

Online NHibernate Documentation

NHibernate available resources

SourceForge project

Book: Jason Dentler’s NHibernate 3.0 Cookbook

http://delicious.com/ajlopez/nhibernate+tutorial

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

July 4, 2010

Generating a solution with AjGenesis using NHibernate Hbm files

Filed under: .NET, AjGenesis, Code Generation, NHibernate, Open Source Projects — ajlopez @ 9:06 pm

Some months ago, I wrote an example of code generation, using .hbm files as the initial model:

Generating Code with AjGenesis Using NHibernate Hbm Files

Since then, I improved the example. You can download from the trunk at Codeplex:

I prepared a ready-to-run package, at my Skydrive:

Examples > AjGenesis > NHibernateMappingExample02.zip

This is its folder structure:

There is two projects: AjFirstExample, and AjTest. The former has only two simple entities. The latter has entities with one-to-many relation. You can generate the code for a complete .NET solution, launching commands:

GenerateAjFirstExample.cmd
GenerateAjTest.cmd

There are “shortcuts” to

GenerateProject AjFirstExample
GenerateProject AjTest

This is the solution generated for AjTest project:

You can run it as a web site:

In this example, the model, the .hbm files, was enriched with the use of meta tags, like in Employee.hbm in AjTest:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
  assembly="AjTest.Entities"
  namespace="AjTest.Entities"
  >
  <class name="Employee" table="employees">
    <meta attribute="SetName">Employees</meta>
    <meta attribute="Descriptor">Employee</meta>
    <meta attribute="SetDescriptor">Employees</meta>
    
    <id name="Id" column="Id" type="Int32">
      <meta attribute="Description">Id</meta>
      <generator class="native"/>
    </id>
    <property name="EmployeeCode" type="String">
      <meta attribute="Description">Employee Code</meta>
    </property>
    <property name="LastName" type="String">
      <meta attribute="Description">Last Name</meta>
    </property>
    <property name="FirstName" type="String">
      <meta attribute="Description">First Name</meta>
    </property>
    <many-to-one name="Department" column="IdDepartment"
                 class="AjTest.Entities.Department, AjTest.Entities" />
    <bag name="Tasks" lazy="true" inverse="true" cascade="all">
      <key column="IdEmployee"/>
      <one-to-many class="AjTest.Entities.Task, AjTest.Entities"/>
    </bag>  
    <bag name="EmployeeSkills" lazy="true" inverse="true" cascade="all">
      <key column="IdEmployee"/>
      <one-to-many class="AjTest.Entities.EmployeeSkill, AjTest.Entities"/>
    </bag>  
  </class>
</hibernate-mapping>

Note the use of the meta tag at class level, and at property level. AjGenesis run tasks, one is Tasks\LoadMappings.ajg:

include "Utilities/Utilities.tpl"
include "Utilities/FileUtilities.tpl"
include "Utilities/TypeUtilities.tpl"
Include("Utilities/NHibernateUtilities.tpl")
include "Templates/CSharp/UtilitiesCs.tpl"
include "Templates/CSharp/CSharpFunctions.tpl"
AssemblyManager.LoadFrom("Libraries/NHibernate.dll")
parser = new NHibernate.Cfg.MappingSchema.MappingDocumentParser()
if not Project.BuildDir then
  Project.BuildDir = "Build/${Project.Name}/CSharp"
end if
Project.Entities = CreateList()
for each MappingName in Project.Mappings
  filename = "Projects/${Project.Name}/Mappings/${MappingName}.hbm.xml"
  mapping = parser.Parse(OpenAsStream(filename))
    
  for each hbmclass in mapping.Items where IsType(hbmclass, "HbmClass")
    Entity = CreateObject()
    
    Project.Entities.Add(Entity)
  
    Entity.ClassName = hbmclass.name
    Entity.Name = hbmclass.name
    Entity.Namespace = mapping.namespace
    
    Message "Processing Mapping of Entity " & Entity.Name
        
    Entity.Properties = CreateList()
    
    if hbmclass.Id then
      Property = CreateObject()
      Property.Name = hbmclass.Id.name
      Property.Type = HbmTypeToCSharp(hbmclass.Id.type1, Entity.Namespace)
      Property.IsId = True
      for each meta in hbmclass.Id.meta
        Property.SetValue(meta.attribute, meta.GetText())
      end for
      Entity.Properties.Add(Property)
    end if
    
    for each meta in hbmclass.meta
      Entity.SetValue(meta.attribute, meta.GetText())
    end for
        
    for each item in hbmclass.Items
      Message "Processing Item " & item.GetType().Name
      
      if IsType(item, "HbmProperty") then
        Property = CreateObject()
        Property.Name = item.name
        Property.SetValue("Description", "Description " & item.name)
        Property.Type = HbmTypeToCSharp(item.type1, Entity.Namespace)
        Entity.Properties.Add(Property)
        for each meta in item.meta
          Property.SetValue(meta.attribute, meta.GetText())
        end for
      end if
      
      if IsType(item, "HbmManyToOne") then
        Property = CreateObject()
        Property.Name = item.name
        Property.Type = HbmTypeToCSharp(item.class, Entity.Namespace)
        Property.Reference = HbmTypeToCSharp(item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
      if IsType(item, "HbmSet") then
        Property = CreateObject()
        Property.Name = item.name
        Property.IsSet = true
        Property.Type = HbmTypeToCSharp(item.Item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
      if IsType(item, "HbmBag") then
        Property = CreateObject()
        Property.Name = item.name
        Property.IsList = true
        Property.Type = HbmTypeToCSharp(item.Item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
    end for    
  end for
end for

Note the use of Property.SetValue(…), Entity.SetValue(…) to enrich the in-memory model representation with the new metadata contained in mapping files. As in other AjGenesis examples, the metadata is used to show legends in presentation files, or for whatever you want to put in the tasks and templates.

This is a “proof-of-concept” example. It should be improved to use all the power of NHibernate. But it’s a demostration of the power of an initial model, to create lot of text artifacts, in this case, a ready-to-run application.

More examples are coming, this time using a free model. Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

November 22, 2009

Generating code with AJGenesis using NHibernate hbm files

Filed under: .NET, AjGenesis, C Sharp, Code Generation, NHibernate — ajlopez @ 9:50 am

I was working on generating C# classes, using as starting point .hbm NHibernate mapping files. As usual, I wrote an example with AjGenesis, my open source code generation engine.

You can download a first example from my Skydrive:

Examples > AjGenesis > NHibernateMappingExample01.zip

(the code is in the trunk, in the current change set, under examples\NHibernateMappinp:

but if you want to go directly to the example, the Skydrive download I mentioned has all you need to run this demo, including AjGenesis trunk code compiled to binaries).

After expanding the file, you have this content:

 

To create C# classes, execute at command prompt:

GenerateClasses AjFirstExample
GenerateClasses AjTest

To create a .NET project with the .cs and .hbm files, run:

GenerateProject AjFirstExample
GenerateProject AjTest

The generated files are created under Build folder.

The two example projects are AjFirstExample, with two simple plain mappings, and AjTest, with a more interesing mapping, with bags and many to one relations.

Currently, each project is described by a simple Project.xml:

<Project Name="AjTest">
</Project>

This is one of the mapping files in Projects\AjTest\Mappings, Department.hbm:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
  assembly="AjTest.Entities"
  namespace="AjTest.Entities"
  >
  <class name="Department" table="departments">
    <id name="Id" column="Id" type="Int32">
      <generator class="native"/>
    </id>
    <property name="Description" type="String"/>
    <bag name="Employees" lazy="true" inverse="true" cascade="all">
      <key column="IdDepartment"/>
      <one-to-many class="AjTest.Entities.Employee, AjTest.Entities"/>
    </bag>  
  </class>
</hibernate-mapping>

This is the generated code for this mapping, Department.generated.cs:

using System;
using System.Collections.Generic;
using Iesi.Collections.Generic;
namespace AjTest.Entities 
{
  public class Department {
    public int Id { get; set; }
    public string Description { get; set; }
    public IList<Employee> Employees { get; set; }
    public Department() 
    {
      this.Employees = new List<Employee>();
    }
  }
}

Lets take a look to generation process. This is GenerateProject.cmd:

@echo off
set ProjectName=%1%
if "%1%"=="" set ProjectName=AjFirstExample
Bin\AjGenesis.Console.exe Projects\%ProjectName%\Project.xml Tasks\AddMappings.ajg Tasks\BuildCSharp.ajg
xcopy Libraries\*.* Build\%ProjectName%\CSharp\Src\Libraries /Y /Q

The main line is the one containing AjGenesis.Console.exe invocation. Project.xml is loaded in memory. The AddMapping.ajg task is loaded and executed, and then, BuildCSharp.ajg task is processed. AddMapping.ajg code (written in AjBasic, the dinamic language currently used by AjGenesis):

' Add mappings from directory if not specified in Project model
Include("Utilities/Utilities.tpl")
if not Project.Mappings then
  Project.Mappings = CreateList()
  
  di = new System.IO.DirectoryInfo("Projects/${Project.Name}/Mappings")
  
  for each fi in di.GetFiles("*.hbm.xml")
    filename = fi.Name
    Project.Mappings.Add(filename.Substring(0, filename.Length - 8))
  end for
end if

It adds the name of mapping files contained in the Mapping folder of the project. A more interesing task is GenerateCSharp.ajg. First, it loads the NHibernate library to use its hbm parser:

include "Utilities/Utilities.tpl"
include "Utilities/FileUtilities.tpl"
include "Utilities/TypeUtilities.tpl"
Include("Utilities/NHibernateUtilities.tpl")
include "Templates/CSharp/UtilitiesCs.tpl"
include "Templates/CSharp/CSharpFunctions.tpl"
AssemblyManager.LoadFrom("Libraries/NHibernate.dll")
parser = new NHibernate.Cfg.MappingSchema.MappingDocumentParser()

Then, it creates the solution and project objects:

if not Project.BuildDir then
  Project.BuildDir = "Build/${Project.Name}/CSharp"
end if
message "Creating Directories..."
FileManager.CreateDirectory(Project.BuildDir)
FileManager.CreateDirectory("${Project.BuildDir}/Sql")
FileManager.CreateDirectory("${Project.BuildDir}/Src")
FileManager.CreateDirectory("${Project.BuildDir}/Src/Libraries")
message "Defining Solution and Projects..."
Project.Solution = CreateObject()
Project.Solution.Guid = "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"
Project.Solution.Projects = CreateList()
message "Defining Entities Project..."
PrjEntities = CreateObject()
PrjEntities.Includes = CreateList()
PrjEntities.Guid = CreateGuid()
PrjEntities.COMGuid = CreateGuid()
Project.Solution.Projects.Add(PrjEntities)
Project.Entities = CreateList()

Then, it iterates on each hbm file, to get information about the entities to generate:

for each MappingName in Project.Mappings
  filename = "Projects/${Project.Name}/Mappings/${MappingName}.hbm.xml"
  mapping = parser.Parse(OpenAsStream(filename))
    
  for each hbmclass in mapping.Items where IsType(hbmclass, "HbmClass")
    Entity = CreateObject()
    
    Project.Entities.Add(Entity)
  
    Entity.ClassName = hbmclass.name
    Entity.Namespace = mapping.namespace
    
    ' Namespace as default project name for Entities Project
    if not PrjEntities.Name then
      PrjEntities.Name = mapping.namespace
      PrjEntities.Directory = "${Project.BuildDir}/Src/${PrjEntities.Name}"
      FileManager.CreateDirectory(PrjEntities.Directory)
    end if
    
    Entity.Properties = CreateList()
    
    if hbmclass.Id then
      Property = CreateObject()
      Property.Name = hbmclass.Id.name
      Property.Type = HbmTypeToCSharp(hbmclass.Id.type1, Entity.Namespace)
      Entity.Properties.Add(Property)
    end if
    
    for each item in hbmclass.Items
      if IsType(item, "HbmProperty") then
        Property = CreateObject()
        Property.Name = item.name
        Property.Type = HbmTypeToCSharp(item.type1, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
      
      if IsType(item, "HbmManyToOne") then
        Property = CreateObject()
        Property.Name = item.name
        Property.Type = HbmTypeToCSharp(item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
      if IsType(item, "HbmSet") then
        Property = CreateObject()
        Property.Name = item.name
        Property.IsSet = true
        Property.Type = HbmTypeToCSharp(item.Item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
      if IsType(item, "HbmBag") then
        Property = CreateObject()
        Property.Name = item.name
        Property.IsList = true
        Property.Type = HbmTypeToCSharp(item.Item.class, Entity.Namespace)
        Entity.Properties.Add(Property)
      end if
    end for    
  end for
end for

You can extend the capabilities, processing more tags (I should write an example using Meta tags), and detecting more NHibernate mapping idioms. Now, the task generates the code:

for each Entity in Project.Entities
  TransformerManager.Transform("Templates/CSharp/Entity.tpl", "${PrjEntities.Directory}/${Entity.ClassName}.generated.cs", Environment)
  PrjEntities.Includes.Add(CreateFileCs("${Entity.ClassName}.generated"))
end for

The tasks not only generates the .cs files, but it creates a solution and a C# project, copying and embedding the original mapping files:

for each MappingName in Project.Mappings
  filename = "Projects/${Project.Name}/Mappings/${MappingName}.hbm.xml"
  targetfilename = "${PrjEntities.Directory}/${MappingName}.hbm.xml"
  System.IO.File.Copy(filename, targetfilename, true)
  PrjEntities.Includes.Add(CreateFileType(MappingName,"hbm.xml"))
end for
for each CsProject in Project.Solution.Projects where CsProject.ProjectType<>"Web"
  FileManager.CreateDirectory(CsProject.Directory)
  FileManager.CreateDirectory(CsProject.Directory & "/Properties")
  TransformerManager.Transform("Templates/CSharp/CsProject.tpl", "${CsProject.Directory}/${CsProject.Name}.csproj", Environment)
  TransformerManager.Transform("Templates/CSharp/AssemblyInfoCs.tpl", "${CsProject.Directory}/Properties/AssemblyInfo.cs", Environment)
end for
TransformerManager.Transform("Templates/Solution.tpl", "${Project.BuildDir}/Src/${Project.Name}.sln", Environment)

This is the generated solution:

Next steps

I should work in these point:

– Generate a more complete solution (with NHibernate infrastructure, Web Presentation, etc…) as in others AjGenesis examples.

– Support more NHibernate mapping options

– Use meta tags

But now, you are able to play with this example. You can change the templates to generate more artifacts, as Visual Basic .NET source files.

Thanks to @fabiomaulo for pointing me to the NHibernate hbm parser capabilities!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Older Posts »

Blog at WordPress.com.