Entity Framework Best Practices In Business Logic?

前端 未结 5 523
北恋
北恋 2020-12-12 11:46

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 separate class in my business logic

相关标签:
5条回答
  • 2020-12-12 12:14

    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.

    0 讨论(0)
  • 2020-12-12 12:18

    In my experience this code is not good, because you lose the capacity to navigate relationships through navigation properties.

    public List<Articles>  getArticles( ){  
        using (var db = new ArticleNetEntities())
        {
            articles = db.Articles.Where(something).ToList();
        }
    }
    

    Using this approach you can't use the following code because a.Members is always null( db context is close and cant get data automatically).

    var articles = Data.getArticles();
       foreach( var a in articles ) {
           if( a.Members.any(p=>p.Name=="miki") ) {
               ...
           }
           else {
               ...
           }
        }
    }
    

    Using only a global db context is a bad idea because you must use a delete changes function

    in a point of your application yo do this but don't save changes and close the window

    var article= globalcontext.getArticleByID(10);
    article.Approved=true;
    

    then in another point of application you make some operation and save

    //..... something
    globalcontext.saveChanges();
    

    in this case previous article approved property is set to modified by entity framework. When you save, approved is set true!!!

    Best approach for me is use 1 context per class You can pass context to another external method if you need

    class EditArticle {
    
        private DbEntities de;
        private currentAricle;
    
        public EditArticle() {
            de = new DbEntities; //inizialize on new istance
        }
    
        loadArticleToEdit(Articele a){
            // a is from another context 
            currentArticle= de.Article.Single(p=>p.IdArticle==a.IdArticle){
        }
    
        private saveChanges(){
            ...
            pe.saveChanges();
        }
    }
    
    0 讨论(0)
  • 2020-12-12 12:21

    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. :)

    0 讨论(0)
  • 2020-12-12 12:25

    You can start preparing Entity Framework from data access layer by creating a generic repository class for all required Entity Framework functions. Then you can used it in Business layer (Encapsulated)

    Here are the best practices that I have used for Entity Framework in data, business, and UI layers

    Techniques used for this practice:

    1. Applying SOLID architecture principles
    2. Using Repository design pattern
    3. Only one class to go (and you will find it ready)
    0 讨论(0)
  • 2020-12-12 12:27

    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.

    0 讨论(0)
提交回复
热议问题