views:

79

answers:

3

I am using the Entity framework for the first time, and would like to know if I am using in the best practice.

I have created a sperate class in my business logic which will handle the entity context. the problem I have, is in all the videos I have seen they usually wrap the context in a using statement to make sure its closed, but obviously I can't do this in my business logic as the context will be closed before I can actually use it?

So is this ok what I'm doing? A couple

    public IEnumerable<Article> GetLatestArticles(bool Authorised) 
    {
        var ctx = new ArticleNetEntities();
        return ctx.Articles.Where(x => x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
    }

    public IEnumerable<Article> GetArticlesByMember(int MemberId, bool Authorised)
    {
        var ctx = new ArticleNetEntities();
        return ctx.Articles.Where(x => x.MemberID == MemberId && x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
    }

I just want to make sure I'm not building something that's going to die when a lot of people use it?

+1  A: 

I would have the ctx as a private variable within each class, then create a new instance of this each time and then dispose when finished.

public class ArticleService
{
    private ArticleEntities _ctx;

    public ArticleService()
    {
        _ctx = new ArticleEntities();
    }

    public IEnumerable<Article> GetLatestArticles(bool Authorised) 
    {            
        return _ctx.Articles.Where(x => x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
    }

    public IEnumerable<Article> GetArticlesByMember(int MemberId, bool Authorised)
    {           
        return _ctx.Articles.Where(x => x.MemberID == MemberId && x.IsApproved == Authorised).OrderBy(x => x.ArticleDate);
    }

    public void Dispose()
    {
        _ctx.Dispose();
        _ctx = null;
    }

}

Then when calling this.

ArticleService articleService = new ArticleService();
IEnumerable<Article> article = articleService.GetLatestArticles(true);
articleService.Dispose(); // killing the connection

This way you can also add/update other objects within the same context and call a save method which saves any changes to the db through the Entity.

Tim B James
Thanks for the example :) Appreciated
leen3o
+3  A: 

It really depends on how to want to expose your repository/data store.

Not sure what you mean by "the context will be closed, therefore i cannot do business logic". Do your business logic inside the using statement. Or if your business logic is in a different class, then let's continue. :)

Some people return concrete collections from their Repository, in which case you can wrap the context in the using statement:

public class ArticleRepository
{
   public List<Article> GetArticles()
   {
      List<Article> articles = null;

      using (var db = new ArticleNetEntities())
      {
         articles = db.Articles.Where(something).Take(some).ToList();
      }
   }
}

Advantage of that is satisfying the good practice with connections - open as late as you can, and close as early as you can.

You can encapsulate all your business logic inside the using statement.

The disadvantages - your Repository becomes aware of business-logic, which i personally do not like, and you end up with a different method for each particular scenario.

The second option - new up a context as part of the Repository, and make it implement IDisposable.

public class ArticleRepository : IDisposable
{
   ArticleNetEntities db;

   public ArticleRepository()
   {
      db = new ArticleNetEntities();
   }

   public List<Article> GetArticles()
   {
      List<Article> articles = null;
      db.Articles.Where(something).Take(some).ToList();
   }

   public void Dispose()
   {
      db.Dispose();
   }

}

And then:

using (var repository = new ArticleRepository())
{
   var articles = repository.GetArticles();
}

Or the third-option (my favourite), use dependency injection. Decouple all the context-work from your Repository, and let the DI container handle disposal of resources:

public class ArticleRepository
{
   private IObjectContext _ctx;

   public ArticleRepository(IObjectContext ctx)
   {
      _ctx = ctx;
   }

   public IQueryable<Article> Find()
   {
      return _ctx.Articles;
   }
}

Your chosen DI container will inject the concrete ObjectContext into the instantiation of the Repository, with a configured lifetime (Singleton, HttpContext, ThreadLocal, etc), and dispose of it based on that configuration.

I have it setup so each HTTP Request gets given a new Context. When the Request is finished, my DI container will automatically dispose of the context.

I also use the Unit of Work pattern here to allow multiple Repositories to work with one Object Context.

You may have also noticed I prefer to return IQueryable from my Repository (as opposed to a concrete List). Much more powerful (yet risky, if you don't understand the implications). My service layer performs the business logic on the IQueryable and then returns the concrete collection to the UI.

That is my far the most powerful option, as it allows a simple as heck Repository, the Unit Of Work manages the context, the Service Layer manages the Business Logic, and the DI container handles the lifetime/disposal of resources/objects.

Let me know if you want more info on that - as there is quite a lot to it, even more than this surprisingly long answer. :)

RPM1984
Wow... Awesome reply thanks - I think I need to do a bit more reading up!
leen3o
No worries. :) Look at some of my other questions/answers - i've been dealing with this recently. I didnt intend this answer to be that long, but i guess i got carried away - after all, it's a pretty involved topic. :)
RPM1984
+1  A: 

What you can also do is store your context at a higher level.

E.g., you can have a static class storing the current context:

class ContextManager
{
    [ThreadStatic]
    public static ArticleEntities CurrentContext;
}

Then, somewhere outside you do something like this:

using (ContextManager.CurrentContext = new ArticleEntities())
{
    IEnumerable<Article> article = articleService.GetLatestArticles(true);
}

Then, inside the GetLastestArticles, you just use the same ContextManager.CurrentContext.

Of course, this is just the basic idea. You can make this a lot more workable by using service providers, IoC and such.

Pieter