views:

50

answers:

2

Hello, I have started to look at the Entity Framework for a project I am doing and going down the road of using a BLL against it via the the repository pattern. As I understand it for each entity I should create a repository for it so I would have

public class UserRepository : IRepository<User>
{ ... }

and

public class AccountRepository : IRepository<Account>
{ ... }

With the examples I have seen it is common practice to create the entities context within a using statement and perform gets, updates and saves etc within.

using(var ctx = new AppEntities()
{
    //do whatever
    ctx.SaveChanges();
}

For simple access to the repository this would be ok, but what if I wanted to compose up an interaction between 2 (or more) repositories within by BLL...

public void SaveSomethingMoreComplex()
{
    //BLL here stuff like validation etc

    _userRepository.GetSomeData();
    _accountRepository.SaveSomeData(account);
    _userRepository.SaveSomeMore(user);

    // Probably should have one final save that affects both repositories???
    // Should be in a transaction scope also?
}

Would it be best to use the same AppEntities instance for both repositories?

Also in this example a final save probably should be at the end of the block rather than having 2 like in my example and part of a transaction?

If I do use the same instance then is it safe to inject that in the constructor of the repositories and have it live for the lifetime of the app or is there some reason the examples I have seen tend to create and dispose within a single method call?

Thanks for any help provided.

A: 

No, you don't want each entity to have a repository. You want to group common sets of functionality into repository classes. All of the account functionality should be one repository. This is common in ASP.NET MVC type apps although I find this isn't best in practice.

If I'm going to go to the effort of adding new functionality to a repository, what I will probably want later is to have this be available on the entity itself so I create partial classes which contain this sort of business logic. That way I can do something like ShoppingCart.AddProduct(int id) and perform the logic in the partial class.

Another common scenario is creating one-off view models.This is actually my preference.

http://blogs.msdn.com/b/dphill/archive/2009/01/31/the-viewmodel-pattern.aspx

Just remember that your entity in Entity Framework is already an abstraction of the data source or can be unlike LINQ To SQL where it is a one to one mapping of the data source.

Paul Mendoza
Thanks, I was considering placing my logic in the partial class but I might want to go with WCF and DTO's so having the logic more in the service might be more appropriate. I will see as I get more into it.
aqwert
+2  A: 

This is actually not that unusual an issue when dealing with the Repository pattern, and what it boils down to is providing a way to explicitly manage the lifecycle of your unit of work (which in the case of entity framework is your context).

You didn't specify if your doing web or windows development, but in the context of web development it is not uncommon to set the lifecycle of your unit of work to a single request. So when your request starts, you create your context, and then when it is over you can call SaveChanges (or whatever it is for entity framework) and that would apply the changes to all of the entities you were messing with during the course of the request.

In a windows/service context you'll probably want to set up some sort of explicit life cycle management for your unit or work, so you can define the scope of the UoW based on what you are doing. I tend to like the Conversation metaphor for wrapping UoW operations, which means I can use something like this:

using(Conversation.Start())
{
    // mess with the entities
} // Dispose on the object returned from Start will 
  // Save Changes and close the session

Of course that is glossing over some exception management stuff in there, which you would want to have so you can roll-back changes in the case of a failure.

As far as implementation goes, it kinda depends on your infrastructure. I typically use an IoC container, so I'll have the call to Conversation.Start() create my Unit Of Work for me, and set up the IoC to return that specific instance, so when I create my Repositories they get the current UoW. You could also make some factory methods on Conversation, so that you could get your Repository instances from the conversation. Kinda depends on the API you want to have available.

Hope this helps.

ckramer
I was hoping to use the BLL and DAL layers for both, but I am starting off with a win app first and see how it goes.
aqwert
Also I coded something quickly up that is similar to your conversation concept (although I like the term conversation better) which can include transaction management. I will definately use IoC whereever I can. Thanks
aqwert
You should be able to re-use the components reasonably easily between winforms and ASP.Net, which is kinda what the IRepository stuff was intended to do. As long as you expose interfaces for the services your working with in the BLL you should be in good shape.
ckramer
I have followed your approach where I can inject an IUnitOfWork<TContext> into the repositories which can get the Current instance of the Context.
aqwert