Click here to Skip to main content
15,886,067 members
Articles / Programming Languages / C#

Simplifying the Entity Framework DbContext w/ Generics

Rate me:
Please Sign up or sign in to vote.
3.33/5 (5 votes)
6 Sep 2017CPOL4 min read 20.1K   9   5
How I simplify my DataContext using Generics and OOP in C#.NET

Introduction

A while back I was working on project that featured a wide set of features for a reporting integration. One of the requirements was that the third party web services be wrapped for seamless integration with existing data that would be accessed using Entity Framework for a customer portal. This article will go over what I did to accomplish one of the clever techniques I used in leveraging generics and OOP to minimize code and boost extensibility and maintenance.

The benefit I get from the focus of this artcile, a Generic DbContext, is that I no longer have to update my context with lists of data sources. I never have to update it again.

Background

I hope this article offers a few techniques I have not seen other developers leverage nor do I see it much online. The breadth of this artcile should also reduce the chances of me covering already well established ground of other articles. The reader should be familiar with Entity Framework and OOP in C#.NET, but I hope to offer enough information that beginners can make use of this article.

There are various situations in which you might be writing your code but I typically suggest to those who ask, that they segregate their Business Logic, and Data Access layers into dynamic linking libraries (DLLs) so they can be versioned, distributed, and plugged/unplugged from existing deployments easily without compiling the entire solution. Because of this I will be speaking with this consideration in mind, while my code example submitted will reflect a simpiler design.

Looking at the Base Classes

First, I try to make better use of base class that all of my components can utilize. Common between my third party service wrapper, and my database access. Normally I would set this inside a common base class DLL like a Utility dll. In the code below you can create a collection for exceptions captured during execution called "ObjectExceptions". It also has has the bool "IsDebugMode" variable that is set int he constructor using the compiler directive #if DEBUG.

One thing you'll notice is that the class is public. This is so I can access it in the Utility.dll, however, if you are using it within a single project you can make it Internal. It is also Abstract so that it can't be used by itself, and must be inherited by subsequent classes.

C#
public abstract class ApplicationObject
    {


        public bool IsDebugMode { get; set; }
        public List<Exception> ObjectExceptions { get; set; }
        public ApplicationObject()
        {
            IsDebugMode = false;
#if DEBUG
            IsDebugMode = true;
#endif
            ObjectExceptions = new List<Exception>();
        }
    }

Inheriting the ApplicationObject is the BaseDataSource; which is also public abrstact. Depending on your circumstance you can make it Internal as well, but I would maintaint the Abstract designation. You'll see it has two constructors, one default and the other setting whether the database connection should be a dev or production data source. This means you set your debug mode if you like, but by default- the compiler implicates which data source the application will use.

Note: the parametered constructor uses a lowercase "isDebugMode" versus the base class's uppercase "IsDebugMode".

C#
public abstract class BaseDataSource : ApplicationObject
    {
        public string DBConfigName { get; set; }

        public BaseDataSource(bool isDebugMode)
        {
            if (isDebugMode)
                DBConfigName = "DevDB_main";
            else
                DBConfigName = "ProdDB_main";
        }

        public BaseDataSource()
        {
            if (IsDebugMode)
                DBConfigName = "DevDB_main";
            else
                DBConfigName = "ProdDB_main";
        }
    }

Of course the two classes above can be combined for simplicity, however, if your intention is to split functionality into various DLLs then these and following separation of concerns will interest you. Below is an empty class called ApplicationContext which can be used to further extend the BaseDataSource with application specific variables if you like.

C#
public class ApplicationContext : BaseDataSource
    {
        public ApplicationContext() : base()
        { }
    }

The Generic DbContext Class

As one can see the GenericaDbContext take a generic parameter T with the constraint that the model being used inherits from the BaseEFModel. This contstraint and the Entity Framework specifics will be well secured from misuse by this and other classes.

The "EFContext" makes use of the ApplicationContext class's database designation and the whatever application specifics placed in the class. It is very simple.

C#
public class GenericDbContext<T> : DbContext where T : BaseEFModel
    {
        public ApplicationContext EFContext { get; set; }
        public GenericDbContext() : base()
        {
            EFContext = new ApplicationContext();
            this.Configuration.AutoDetectChangesEnabled = false;
            this.Database.Connection.ConnectionString =
                System.Configuration.ConfigurationManager
                   .ConnectionStrings[EFContext.DBConfigName].ConnectionString.ToString();
        }

        public DbSet<T> GenericData { get; set; }
    }

Using the New Generic Database Context

A simple use of the new context is below. One can of course make use of Linq or Lambda Expressions as they see fit. Because of this design, as long as your EF model inherits from the "BaseEFModel" you won't have to update your database context code anymore.

C#
var model = new GenericDbContext<TestModel>().GenericData.ToList<TestModel>(); 

Points of Interest and In Closing

I believe this to be a very simple use of OOP and generics in the simplification of the database context. The best part is that the code, once placed in its architecturally beneficial locations, will allow for extensibility of commonly used data access items. I hope this helps some people out instead of having massive lists of context entries they'd have to update, they can code it once and never touch it again.

History

none

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
United States United States
Full stack .NET developer with over fifteen years experience. I currently work as a consultant architect building full stack applications in MVC.NET but also facilitate a number of other roles. I don't post here much, but I should.

Comments and Discussions

 
QuestionProject Sample Pin
Member 1336503622-Sep-17 6:22
Member 1336503622-Sep-17 6:22 
AnswerRe: Project Sample Pin
Jim_Gray25-Oct-17 17:49
Jim_Gray25-Oct-17 17:49 
GeneralRe: Project Sample Pin
Member 1336503627-Jul-18 21:50
Member 1336503627-Jul-18 21:50 
SuggestionProvide full example PinPopular
Klaus Luedenscheidt6-Sep-17 19:11
Klaus Luedenscheidt6-Sep-17 19:11 
GeneralRe: Provide full example Pin
Jim_Gray25-Oct-17 17:48
Jim_Gray25-Oct-17 17:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.