65.9K
CodeProject 正在变化。 阅读更多。
Home

使用泛型简化 Entity Framework DbContext

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.33/5 (5投票s)

2017年9月6日

CPOL

4分钟阅读

viewsIcon

22050

如何在 C#.NET 中使用泛型和 OOP 简化我的 DataContext

引言

前段时间,我正在做一个项目,该项目具有用于报表集成的广泛功能。其中一个要求是包装第三方 Web 服务,以便与使用 Entity Framework 访问的现有数据无缝集成,用于客户门户。本文将介绍我如何使用一种巧妙的技术,利用泛型和 OOP 来最小化代码并提高可扩展性和可维护性。

我从本文的重点,一个泛型 DbContext 中获得的好处是,我不再需要使用数据源列表来更新我的上下文。 我再也不需要更新它了。

背景

我希望本文提供一些我没有看到其他开发人员使用的技术,或者我在网上很少看到这些技术。本文的广度也应减少我涵盖其他文章中已建立的基础的可能性。读者应该熟悉 Entity Framework 和 C#.NET 中的 OOP,但我希望提供足够的信息,以便初学者可以利用本文。

在各种情况下您可能会编写代码,但我通常建议那些询问的人将他们的业务逻辑和数据访问层分离到动态链接库 (DLL) 中,以便可以轻松地对它们进行版本控制、分发和插入/拔出到现有部署中,而无需编译整个解决方案。 因此,我将牢记这一点进行说明,而我提交的代码示例将反映一个更简单的设计。

查看基类

首先,我尝试更好地利用我的所有组件都可以使用的基类。我的第三方服务包装器和数据库访问之间是通用的。通常我会将此设置在公共基类 DLL 中,例如 Utility dll。在下面的代码中,您可以创建一个集合,用于捕获执行期间的异常,称为“ObjectExceptions”。它还具有布尔值“IsDebugMode”变量,该变量使用编译器指令 #if DEBUG 在构造函数中设置。

您会注意到的一件事是该类是公共的。 这样我就可以在 Utility.dll 中访问它,但是,如果您在一个项目中使用它,您可以将其设为 Internal。它也是 Abstract,因此它不能单独使用,并且必须由后续类继承。

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>();
        }
    }

继承 ApplicationObject 的是 BaseDataSource;它也是公共抽象的。根据您的情况,您也可以将其设为 Internal,但我将保持 Abstract 指定。您会看到它有两个构造函数,一个默认构造函数,另一个用于设置数据库连接应该是开发数据源还是生产数据源。这意味着您可以根据需要设置调试模式,但默认情况下,编译器会暗示应用程序将使用哪个数据源。

注意:带参数的构造函数使用小写的“isDebugMode”而不是基类的大写的“IsDebugMode”。

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";
        }
    }

当然,为了简单起见,可以将上面的两个类组合起来,但是,如果您的目的是将功能拆分为各种 DLL,那么这些以及以下关注点分离将使您感兴趣。下面是一个名为 ApplicationContext 的空类,如果需要,可以使用它来进一步扩展具有应用程序特定变量的 BaseDataSource。

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

泛型 DbContext 类

可以看出,GenericaDbContext 采用泛型参数 T,并约束所使用的模型继承自 BaseEFModel。通过此类和其他类,可以很好地保护此约束和 Entity Framework 的具体细节,使其免受滥用。

"EFContext" 利用 ApplicationContext 类的数据库指定和放置在该类中的任何应用程序细节。 这很简单。

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; }
    }

使用新的泛型数据库上下文

下面是新上下文的一个简单用法。当然,人们可以根据自己的需要使用 Linq 或 Lambda 表达式。由于这种设计,只要您的 EF 模型继承自“BaseEFModel”,您就不必再更新您的数据库上下文代码。

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

关注点和结束语

我认为这是在简化数据库上下文时对 OOP 和泛型的一种非常简单的使用。最好的部分是,一旦代码被放置在其架构上有利的位置,它将允许扩展常用数据访问项。我希望这能帮助一些人,而不是让他们拥有大量必须更新的上下文条目列表,他们可以编写一次代码并且永远不再接触它。

历史

none

© . All rights reserved.