将数据库上下文提供给对象Factory

时间:2017-03-30 14:00:06

标签: c# entity-framework design-patterns dbcontext factory-pattern

当我在代码中使用工厂模式(C#,但它适用于我认为的任何语言)时,我总会问自己一个问题。

我有一个"服务"负责与我的数据库交互,处理对象并与我的对象模型交互。

此服务有时会使用Factory来委派对象的实例化。 但是这个工厂显然需要与数据库进行交互以正确地实现我的对象。 例如,将数据库上下文传递给Create方法是一种好/坏的做法吗?

像这样:

var myNewObject = MyFactory.Create(myDatabaseContext);

另一种方式是让服务始终唯一一个与数据库交谈。

var myNewObject = MyFactory.Create();
var extraProperty = myDatabaseContext.Get(something);
myNewObject.extraProp = extraProperty;

有任何建议吗?

2 个答案:

答案 0 :(得分:4)

将数据库上下文传递到工厂创建方法的想法称为方法注入。这是依赖注入的一种形式,因此您处于正确的轨道上。

您可以使用依赖注入通过构造函数管理工厂内的数据库上下文。工厂看起来像这样:

public class MyFactory 
{
    private readonly IMyDbContext dbContext;

    public MyFactory(IMyDbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public object Create()
    {
        // Use the dbContext, etc
    }
}

构造函数注入通常是受欢迎的,因为它使方法签名不那么混乱。我们也很可能有一种类型的数据库上下文,因此不需要根据其他运行时信息利用多态性。

您可以选择使用依赖注入容器(如Ninject或我最喜欢的SimpleInjector)来管理依赖关系。

只有工厂才能使用DbContext。您可能需要注意的一件事是您工厂的用户可能没有意识到工厂正在调用数据库。这可能是一件坏事,并且会对性能产生负面影响。通常,构造信息将传递到工厂方法,而不是从DB初始化为工厂方法。您甚至可以更进一步使用Repository Pattern来抽象出更多的数据访问逻辑,如果您认为有必要并且您还没有。

如果您不熟悉,请详细了解依赖注入,you can start here

我的理想结构可能如下所示:

public class MyFactory : IFactory
{  
    public object Create(object someProperty)
    {
        // build object
    }
}

public class MyService
{
    private readonly IMyDbContext dbContext;
    private readonly IFactory factory;

    public MyService(IMyDbContext dbContext, IFactory factory)
    {
        this.dbContext = dbContext;
        this.factory = factory;
    }

    public void DoWork()
    {
        var property = dbContext.Get(something);
        var newObj = factory.Create(property);
        // Use stuff
    }
}

答案 1 :(得分:1)

在我正在处理的项目中,我们尝试在服务中保留所有数据库访问权限。如果Factory需要必须从DB加载的对象,则服务应加载它们并将它们传递给Factory。如果工厂返回的对象必须保留,则服务应将其添加到DbContext。

这与您展示的第二种方式相对应。优点是Factory可以进行单元测试,无需模拟DbContext。

如果你想在工厂内保持数据库访问,我会将DbContext注入Factory的构造函数,而不是将其传递给Create()方法。

服务获取工厂的实例依次注入(而不是访问工厂的静态方法)。再次,这将使模拟更容易。

public class Service {

    private readonly IMyDbContext _myDatabaseContext;
    private readonly IMyFactory _myfactory;

    public Service (IMyDbContext myDbContext, IMyFactory myfactory) {
        _myDatabaseContext = myDbContext;
        _myfactory = myfactory
    }

    public void Create() {
        var extraProperty = myDatabaseContext.Get(something);
        var myNewObject = _myFactory.Create(extraProperty);
        _myDatabaseContext.Add(myNewObject);
        _myDatabaseContext.SaveChanges();
    }
}