【问题标题】:Ripe for refactoring - .NET dependency injection重构的成熟——.NET 依赖注入
【发布时间】:2011-09-11 15:18:01
【问题描述】:

与大多数人一样,我已经开始了解实体框架的某些细节。其中之一是上下文的生命周期。我正在使用存储库并已决定上下文将在请求的长度内存在。因此,无论在何处使用该存储库,都需要从 Web 层注入上下文。

我已经编写了一些我确信可以重构的代码(事实上,绝对可以!)。那么基于上面的概念,你会如何优化下面的仓库助手呢?

public class RepositoryHelper
{

    public static CountryRepository GetCountryRepository() {
        return new CountryRepository(HttpContext.Current.GetObjectContext());
    }

    public static CurrencyRepository GetCurrencyRepository()
    {
        return new CurrencyRepository(HttpContext.Current.GetObjectContext());
    }

    public static SettingRepository GetSettingRepository()
    {
        return new SettingRepository(HttpContext.Current.GetObjectContext());
    }

}

存储库非常简单,看起来像

public class CountryRepository
{

    private Context _context = null;
    public CountryRepository(Context context)
    {
        _context = context;
    }

    public Country GetById(int id) 
    {
        // Would return a country
    }

    public IEnumerable<Country> All()
    {
        // Would return a list of countries
    }

}

【问题讨论】:

    标签: c# .net entity-framework interface dependency-injection


    【解决方案1】:

    这里的挑战是,您构建的不是存储库模式意义上的存储库。存储库模式的一个目标是从问题域中抽象出数据访问层的实现。它是通过一个存储库完成的,该存储库的行为类似于内存中的域对象集合,您可以使用它执行正常的 CRUD 功能以及一些更具体的操作,即 GetByID(id)。

    然后存储库对应用程序隐藏实际的持久层,实际上允许您在不影响应用程序的情况下更改该层,即您可以先将数据存储在平面文件中,然后再转移到 RDBMS。

    您通常会创建一个接口来描述您的存储库需要实现的方法,并使用该接口作为类型实际传递存储库实例。这是抽象,该接口在您的存储库的所有可能的具体实现中都是通用的,但您的应用程序却没有注意到(在一定程度上)实际上正在使用哪个接口。

    我建议退后一步,再次查看存储库模式,看看是否需要它。确保您不只是为了它而实施它,并且您不会不必要地增加应用程序的复杂性。确定数据访问方法后,您可以查看如何最好地利用现有的 EF 上下文。

    【讨论】:

    • 谢谢拉撒路。为了清楚起见,我已经修改了示例 repo(以防我的示例不完整)。我认为存储库模式已正确用于数据访问,并且与解决方案中的 Web 域是分开的。您的第三段是我最感兴趣的 - 即我的 Web 层如何与这些存储库交互,而无需我编写一个为每种存储库类型注入上下文的愚蠢助手。
    • @Maleks:我使用 DI 容器(Castle Windsor)在实例化存储库时实例化上下文(当活动控制器需要它时,它本身由 DI 容器实例化)。每个存储库都应该基于与您的 Web 应用程序交互的聚合根实体,这超出了此上下文的范围,无法深入探讨。存储库的具体实现可以与数据访问层更紧密地耦合,这几乎是不可避免的,但应用程序与存储库的耦合应该是松散的。
    • 我同意你的观点 Lazerus。将尝试从面向领域的 N-Layered .NET 4.0 应用程序示例(DDD 架构)示例项目 @microsoftnlayerapp.codeplex.com 中获取具体示例
    • @Maleks:将其用作参考的好主意!
    【解决方案2】:

    阅读我的回答here,了解如何制作通用会话管理器。

    然后创建一个 EntityFramework 会话管理器(它存储对象上下文)。

    一些半完成的伪代码:

    public static class EntityFrameworkSession
    {
        [ThreadStatic] private static ObjectContext _current;
    
        public static AssignToSessionFactory()
        {
             SessionFactory.Created += OnCreateObjectContext;
             SessionFactory.Disposed += OnDisposeContext;
        }
    
        public static void OnDisposeContext(object source, SessionEventArgs e)
        {
             if (e.Saved)
               _myContext.SaveChanges();
        }
    }
    

    并在您的存储库中使用:

    EntityFrameworkSession.Current
    

    访问上下文。

    【讨论】:

      【解决方案3】:

      对于 DI,您可以使用 Ninject 并在绑定对象时使用 InRequestScope 方法。

      【讨论】:

        【解决方案4】:

        我认为你会从使用 Repository Provider 类和 Repository Factories 中受益,就像C#/EF and the Repository Pattern: Where to put the ObjectContext in a solution with multiple repositories? 的答案一样。

        【讨论】:

        • 你为什么不让它打字安全?
        • @jgauffin,你能改一下你的问题吗
        • 这看起来很有趣。我很想看看 IRepository 的示例以及您如何使用 repo 提供程序。
        猜你喜欢
        • 1970-01-01
        • 2017-11-22
        • 2016-05-22
        • 1970-01-01
        • 2020-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-03
        相关资源
        最近更新 更多