Implementing the Repository Pattern with LLBLGEN

Tags: , ,
Posted in Development

This post has been sitting in draft for a while but finally managed to get round to completing it. I started it back in 2009. Apologies for the delay :)

It was the start of 2009, and I was investigating ORM tools for a new project we were working on at Clyral. We had been using Linq 2 SQL as our core database access layer for some time but felt we had outgrown it and were looking for something a bit more powerful and flexible. It didn’t take long for us to discover LLBLGEN. Whilst not the most intuitive acronym for an O/R mapping framework, LLBLGEN (Lower Level Business logic Layer Generator) impressed the team from the outset. After downloading the demo version and playing around with it on a test project we committed to purchasing it and since then haven’t looked back.

We started off using the Self Servicing model of the framework as it was earmarked for beginners, in time though, we began to see that we would get more mileage using the adapter model and began using this model as the defacto standard for projects. It was at this point we began looking at ways to implement the repository pattern which simplifies the testing process and ensures the implementation (which is often technology specific) does not get mangled with the domain model. To achieve this we needed every entity to implement an interface (or contract if you will). The problem with this of course, is that in C# generic variance is not supported. This posed a bit of a problem because we still wanted the full representation of a given entity graph to be available using our defined interfaces. To get around this, we needed to update the LLBLGEN templates to allow us to inject our own custom implementation of collections which would match our interface definitions. I have provided a few example snippets to illustrate what I am talking about. Essentially we added properties which took a Todos collection (property of a TodoList entity) such as defined below:

public virtual EntityCollection<TodoEntity> Todos
{
	get
	{
		if(_todos==null)
		{
			_todos = new EntityCollection<TodoEntity>(EntityFactoryCache2.GetEntityFactory(typeof(TodoEntityFactory)));
			_todos.SetContainingEntityInfo(this, "Todolists");
		}
		return _todos;
	}
}

and added the code below to support out interface definition:

public EntityList<ITodoEntity, TodoEntity>  TodosCollection
{
	get
	{
		if (_TodosCollection == null)
		{
			_TodosCollection = new EntityList<ITodoEntity, TodoEntity>(this.Todos);
		}
		return _TodosCollection;
	}
}

private EntityList<ITodoEntity, TodoEntity>  _TodosCollection;

where “EntityList” is a custom wrapper we wrote to get around the generic variance issue (note that EntityList understands that a TodoEntity is an implementation of ITodoEntity). This allowed us to define our entity contracts as such:


    /// <summary>
    /// Interface for the entity 'TodoList'.
    /// </summary>
	public partial interface ITodoListEntity 
	{
		EntityList<ITodoEntity, TodoEntity>  TodosCollection {get;}		

	
		System.Int32 Id {get;set;}
		System.String Title {get;set;}
		System.String Description {get;set;}
		System.Int32 ProjectId {get;set;}
		System.Int16 Position {get;set;}
		System.Boolean Billable {get;set;}
		System.DateTime CreatedOn {get;set;}
		System.DateTime ModifiedOn {get;set;}
		System.String CreatedBy {get;set;}
		System.String ModifiedBy {get;set;}
		System.Guid CreatedUserId {get;set;}
		System.Guid ModifiedUserId {get;set;}
	}

As you can see, a standard was implemented where the original list’s name was simply extended with the word “Collection”. After modifying the adapter’s templates and generating our templates to create the entity contracts, everything fell into place and we had our repository pattern implemented. Our repository definitions ensured that only interfaces were passed round (of course implemented using LLBLGEN’s entities) which in turn ensured that our UI (or business logic) knew nothing about the underlying implementation. One benefit of doing this is that the chaps working on the UI never had to deal with the copious number of properties and methods that hang off an LLBLGEN entity by default. Of course, these properties and methods are useful in some cases and can still be used within the repository itself.

I have attached a zip file to this post with the implementation of the EntityList class as well as the templates that we modified and added to make this all happen. Let me know what you think, any comments or suggestions regarding the implementation are certainly welcome!

Rohland

Templates and supporting files


17 Responses

  1. Jowen Mei says:

    Hey Rohland,

    This is good stuff man! This is exactly what I was looking for… thanks for sharing it!

    regards, Jowen Mei

  2. [...] term without too much work. From a code perspective, we implemented the repository pattern using custom LLBLGEN templates. At the repository level, queries were developed using LLBLGEN’s LINQ [...]

  3. Sam says:

    Hi Rohland,

    What you’ve got so far is awesome and I applaud your efforts whole-heartedly. It looks like a massive amount of effort went into it.

    I’m only having trouble when I try to use it myself. When I generate the entities and then try to compile my solution, I get the error of “The type DAL.EntityClasses.OrdersEntity cannot be used as type parameter ‘LLBT’ in the generic type or method DAL.EntityList. There is no implicit conversion from OrdersEntity to IOrdersEntity.” I thought that was the issue you were trying to address in this post.

    Am I missing something perhaps about the implementation?

    Thanks,
    Sam.

  4. Sam says:

    Hi again,

    Almost as soon as I wrote that, I figured out that the reason that it wasn’t working is that I didn’t have OrdersEntity implementing IOrdersEntity. I guess maybe actually writing it done gave me the “a ha!’ moment.

    However, if anyone else is stuck on this, I advise you to have a look at this. Don’t forget to add your reference to DAL.EntityContracts!

    Otherwise, really great work again Rohland. I’m terribly impressed! :)

  5. Rohland says:

    Hi Sam,

    Glad this post helped you! The entities should have been auto-generated with the relevant interface implementations (i.e. the template supplied should have generated OrdersEntity implementing IOrdersEntity, you should not have had to configure this manually). The attachment included the entity template files that you need to setup for LLBLGEN. One of the issues that I haven’t resolved yet is that the interface files generated don’t get included in the Visual Studio project automatically.

    Cheers,
    Rohland

  6. Sam says:

    Hi Rohland,

    Unfortunately, the template that I downloaded did not add the Interface automatically. I made the following change to the entityAdapter.template file:

    public partial class Entity : EntityCommonEntityBase, ISerializable, , IEntity

    That is, I added IEntity just before the UserCodeRegion Additionalinterfaces. That seemed to do the trick.

    However, now I’m facing this issue that the generated entities do not implement all of the interface. Did you take the part out about mapped relations from your EntityAdapterInterface.template or did you add something to the entityAdapter.template? I’ve taken it out temporarily to allow the solution to build, but I feel that I’m going to need those relations later so I’m trying to play around and get it to work still.

    Of course, it could be that the files that I downloaded are a little out of date as compared to what your using. Is that possible?

    I’m not too sure how to get VS to add the interfaces automatically either. I’ve just added them manually so far.

    Thanks,
    Sam.

    Btw, thanks for getting back to my original comment so fast!

  7. Rohland says:

    Perhaps it has something to do with the version of LLBLGEN you are running? We currently use 2.6. The template included in the download (LLBLGEN Customisations\Templates\SharedTemplates\Net2.x\C#\entityadapter.template) does setup the interface references (line 38). Just make sure you follow all the instructions in the Readme.txt.

    If you are still not having any joy, I’ll pull the latest set of templates out and post them here.

  8. Sam says:

    I think I know what happened. Instead of just downloading and copying over your changed files, I had to merge them in with our own and must have corrupted them somehow the first time. I tried it again and now it works great. Sorry about the confusion.

    The only thing I’m trying to figure out now is that one of our databases has a table with a read only field. The resulting entity has no setter, but the template generates one and then the compiler throws an error saying that we’ve missed the implementation. I’m going to tweak it and see what I can come up with. I’ll let you know what I find out if you’re interested. :)

    Thanks again for a great template. It’s really opened my eyes as to what’s possible with LLBLGen.

  9. Rohland says:

    Cool. The latest template I am using deals with the ‘readonly’ issue. Update your interface template for property fields as follows:

    < [If IsNullable]>< [If IsValueType]>< [TypeOfField]>?< [Else]>< [TypeOfField]>< [EndIf]>< [Else]>< [TypeOfField]>< [EndIf]> < [EntityFieldName]> {get;< [If IsReadOnly ]>< [If IsPrimaryKey ]>set;< [EndIf]>< [Else]>set;< [EndIf]>}< [NextForeach]>

  10. Mike says:

    Hi Rohland,

    Thanks for sharing this solution – I’m sure a lot of work went into this!

    I’m currently looking at LLBL for my next project and was wondering if you could share some thoughts on how you implemented the repositories themselves? I’ve tried (without success) to create a basic generic repository but I just can’t get it to work with LLBL. Did you create a specific repository for each of your entities (roots)?

    Thanks again,

    Mike

  11. Rohland says:

    Hi Mike,

    My specific repositories are sub-classes of a base repository which generically handles the boring stuff (GetById, Save – update/insert, Delete).

    I’ll post a blog entry soon on my implementation of the base repository class.

    Regards,
    Rohland

  12. Mike says:

    Thanks Rohland. I did manage to figure out the generic base repository problem I had after finding a way to set the primary key.

    An entry on your repositories would be much appreciated!

    Mike

  13. saravana says:

    Hi Rohland,

    We are going to develop a 3-tier application using WPF,Oracle 11g,LLBLGen 3.0. Do you have a idea for generating Business objects for LLBLGen entties? My client is suggesting to use DAL entities in BL also and return it to UI. But I didn’t like that as it will strongly couple the DAL to UI. Do you have a sample implementation of BL based on LLBLGen entities?

  14. Rohland says:

    Hi,

    The templates attached to this post mitigate that issue since the entities all implement their own defined interfaces. This means the UI is not exposed to ANY LLBLGEN functionality.

    For example, instead of the repository returning an OrderEntity (LLBLGEN entity) it returns an IOrderEntity which is implemented by the LLBLGEN entity but doesn’t expose all the LLBLGEN properties and methods.

    Hope this explanation helps.

  15. James says:

    Any chance you could include a couple blurbs on the repository implementation you are using to wrap all of this.

    And more specifically, do you have a specification or query pattern implementation in your repositories (i.e.: GetBySpec(ISpecification spec) …). Something like that.

    That has traditionally been the bigger challenge I’ve seen with using interfaces in your entity model.

    I suppose that since you are bringing in the LLBLGen dll into your BL with EntityList, maybe you could wrap the specification pattern around some of the llbl functionality.

    Without being able to completely remove LLBL from the BL (kind of ironic, given the name), I currently continue to opt to use the adapter entity classes as-is, same with EF STEs if I’m using Entity Framework. So, I get married to the ORM in a way in a project, but it provides the flexibility in the querying abstraction.

    Would love to hear your views on this.

  16. Sam says:

    Hi Rohland,

    Why did you decide to check for IsReadOnly as well as IsPrimaryKey? What difference does it make to the getter? Was it so that the primary key would be settable like Mike mentioned?

    Also, I’d like to second that I’d be interested in knowing how you implemented the base repository class. I’m having difficulty finding resources the define the repository pattern outside of MVC, so I’d be very interested to see how someone else has tackled it.

    Thanks again for some awesome work,
    Sam.

  17. Rohland says:

    Yeah, that was the reason. The primary key is settable for scenarios where you want to run an update without fetching the entity beforehand.

    Hopefully I’ll get round to posting an article on the actual repositories soon.

Leave a Reply