n层实体框架解决方案的依赖注入


12

我当前正在设计一个使用实体框架5(.net 4)作为其数据访问策略的n层解决方案,但是我担心如何合并依赖项注入以使其可测试/灵活。

我当前的解决方案布局如下(我的解决方案称为Alcatraz):

Alcatraz.WebUI:一个asp.net Webform项目(前端用户界面)引用项目Alcatraz.BusinessAlcatraz.Data.Models

Alcatraz.Business:一个类库项目,包含业务逻辑,引用项目Alcatraz.Data.AccessAlcatraz.Data.Models

Alcatraz.Data.Access:一个类库项目,包含AlcatrazModel.edmxAlcatrazEntitiesDbContext,引用项目Alcatraz.Data.Models

Alcatraz.Data.Models:一个类库项目,包含Alcatraz模型的POCO,无引用。

我对这个解决方案如何工作的愿景是,Web-ui将实例化业务库中的存储库,该存储库将具有(通过构造函数)连接字符串(而不是AlcatrazEntities实例)的依赖项。Web用户界面会知道数据库连接字符串,但不知道它是一个实体框架连接字符串。

在业务项目中:

public class InmateRepository : IInmateRepository
{
    private string _connectionString;

    public InmateRepository(string connectionString)
    {
        if (connectionString == null)
        {
            throw new ArgumentNullException("connectionString");
        }

        EntityConnectionStringBuilder connectionBuilder = new EntityConnectionStringBuilder();

        connectionBuilder.Metadata = "res://*/AlcatrazModel.csdl|res://*/AlcatrazModel.ssdl|res://*/AlcatrazModel.msl";
        connectionBuilder.Provider = "System.Data.SqlClient";
        connectionBuilder.ProviderConnectionString = connectionString;

        _connectionString = connectionBuilder.ToString();
    }

    public IQueryable<Inmate> GetAllInmates()
    {
        AlcatrazEntities ents = new AlcatrazEntities(_connectionString);

        return ents.Inmates;
    }
}

在Web UI中:

IInmateRepository inmateRepo = new InmateRepository(@"data source=MATTHEW-PC\SQLEXPRESS;initial catalog=Alcatraz;integrated security=True;");

List<Inmate> deathRowInmates = inmateRepo.GetAllInmates().Where(i => i.OnDeathRow).ToList();

我对此设计有一些相关的问题。

  1. 就实体框架功能而言,这种设计甚至有意义吗?我听说实体框架已经使用了工作单元模式,是否只是在不必要地添加了另一层抽象?

  2. 我不希望我的Web用户界面直接与Entity Framework进行通信(或什至引用它),我希望所有数据库访问都通过业务层,因为将来我将有多个使用同一业务层的项目(Web服务,Windows应用程序等),我想通过在一个中央区域中放置业务逻辑来轻松维护/更新。这是实现此目标的合适方法吗?

  3. 业务层应该包含存储库,还是应该包含在访问层中?如果它们在哪里,那么传递连接字符串是否是一个很好的依赖关系?

感谢您抽出宝贵的时间阅读!

Answers:


11

您做DI的方式是错误的。

首先,连接字符串属于数据层。或在web.config文件中。

您将要处理的下一个抽象是DbContext,而不是连接字符串。您的存储库不应该了解连接字符串。您的业​​务逻辑将不了解DbContext等。

您的用户界面不知道,并且不会实例化与EF相关的任何内容。

您的观点的具体答案:

  1. 在您对EF非常熟悉之前,请勿添加抽象。它已经添加了良好的抽象,例如UoW,查询,使用POCO等。

  2. 为了使DI起作用,您必须具有一个“构成根”,它引用了所需的所有组件。它可能在WebUI项目中,也可能不在。如果不是,您应该期望它没有引用EF或任何其他与数据相关的技术。

  3. 就在这里停下来 停止在抽象之上添加抽象。从直接的“天真”架构开始,并随着时间的推移进行开发。

抽象是处理复杂性的工具。缺乏复杂性意味着还不需要抽象。


明确地说,我理解您在说什么:存储库(接口存在于业务中,具体存在于Alcatraz.Data.Access?中)接受a DbContext作为其依赖项。业务类具有存储库作为依赖项。对于依赖项注入,我正在手动执行此操作(因此我了解发生了什么)。我希望能够在上设置连接字符串的原因DbContext是我使用数据库分片,因此在某些情况下,我需要具有实体框架才能连接到不同的数据库(具有相同的结构)。我能正确理解你吗?
马修

从您提供的代码来看,您似乎根本没有进行DI。DI的主要目标是使您和您的代码从管理依赖关系中解放出来。我无法想象您没有DI容器就可以手动有效地做到这一点。
鲍里斯·扬科夫

还可以通过DI放心。我已经很有趣了,然后在其他论坛上问了完全相同的问题,以获得相反的答案。DI是一种模式,而不是架构。根据您的目标,您可以决定是否使用它。我使用它,但不是出于大多数人告诉我使用它的原因。
巴斯蒂安·范丹姆

4

一些简短的评论。我个人可能不会传递连接字符串。如果有什么尝试,我可能会尝试创建存储库的接口,然后只是传递接口?让存储库实现或公开IOW接口。

这样,就不必成为实现您的存储库的数据库。它们可以是内存缓存,也可以是任何东西。也许然后您甚至可以使用某种依赖注入框架来实例化这些依赖注入框架?

因此,请回答您的一些问题:

  1. 是的,我认为还可以
  2. 我仍然需要UI参考EF项目和EF存储库层实现的商务层参考接口。这样,其他项目仍然可以使用相同的程序集,但是如果需要,它们可以灵活地交换出来吗?
  3. hmmm,可能是访问层中的存储库,但是实现了在业务层中公开的接口定义?

这些只是思考的想法。


关于第2点,我试图制定的一个目标是不要在ui层中直接使用CRUD。我的意思是,我想确保通过业务层以这种方式进行管理只能发生CRUD。
马修
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.