【问题标题】:MEF and dynamic decision on instance creationMEF 和实例创建的动态决策
【发布时间】:2011-10-17 23:27:37
【问题描述】:

这可能是一个奇怪的情况,但我有时想在使用 MEF 获取导出时重用同一个实例,有时会创建一个新实例。

基本上我有一个 WCF 服务类,每次调用都是实例。每个实例导入一个 RepositoryFactory,它也是每个服务类的新实例。我在工厂中返回一个存储库,并且一个存储库注入了一个 IDbContext。

我希望 Factory 的每个实例都注入相同的 IDbContext 实例,但在 Factory 实例之间具有单独的实例。

所以:

1) Factory1 is created
2) Factory1 creates Repository1-1 that gets IDbContext1 injected
3) Factory1 creates Repository1-2 that gets IDbContext1 injected
4) Factory2 is created
5) Factory2 creates Repository2-1 that gets IDbContext2 injected
6) Factory2 creates Repository2-2 that gets IDbContext2 injected

这应该确保从同一工厂创建的存储库共享一个工作单元。

但作为 MEF 的新手,我不知道该怎么做。


编辑

这是我得到的:

public class RepositoryFactory
{
    private readonly CompositionContainer _container;

    [Import(RequiredCreationPolicy=CreationPolicy.NonShared)]
    private readonly IDbContext _context;

    public IRepository<T> CreateRepository<T>() where T : class, IEntity
    {
        //Somehow add the _context instance into the Repository import

        return _container.GetExportedValue<EntityRepository<T>>();
    }
}

然后

public class EntityRepository<T> : IRepository<T> where T : class, IEntity
{
    // Perhaps a contract name might help!!
    [Import(RequiredCreationPolicy=CreationPolicy.Shared)]
    protected readonly IDbContext _context;

【问题讨论】:

  • 我的一个想法是将上下文导入工厂并以某种方式使其成为将导出到创建的存储库的实例。
  • 除了 Unity the IoC container stackoverflow.com/questions/787001/…,这里是同样的问题

标签: dependency-injection repository mef unit-of-work


【解决方案1】:

您无法使用 MEF 完成此操作;无论您做什么,MEF 容器都不会正确地充当您的工作单元管理器,它不是为此而生的。

您应该尝试显式编写工作单元基础架构以供 DAL 使用。您的存储库应明确要求工作单元管理器提供当前工作单元以及相应的上下文。

看一下NCommonhttps://github.com/riteshrao/ncommon中的代码;您可以重构工作单元功能以满足您的需求。

【讨论】:

  • 嗯,这种类型的操作不仅仅在 UnitOfWork 中有用。我很确定 IoC 容器确实提供了类似的东西,而 MEF 提到了 PartCreator (我找不到)。它实际上是为了更好地控制您的进出口。
  • 其他 IoC 容器提供此功能是正确的,但我不相信 MEF 目前提供;您很可能最早必须等到 .NET 4.5。就像您在上面的评论中提到的那样,它很可能涉及配置 MEF 以将对象实例化委托给您的工厂。如果您为 .NET 4.0 找到这样的解决方案,我会非常感兴趣
  • 好的,我想出了一个不真正使用 MEF 的解决方案,但它让工厂负责确保存储库在从某个工厂实例创建时共享实例。 stackoverflow.com/questions/7725190/…
  • 因此,每次调用服务的每个实例都会创建自己的 RepositoryFactory 实例,该实例用于提供所有 Repository 实例,因此它们共享相同的上下文。我假设使用此解决方案,您对服务的调用非常简单,没有需要跨服务实例关联的长时间运行的过程或服务方法调用?如果是这种情况,这应该可以正常工作,但您很快会发现此解决方案不够灵活,无法处理更复杂的服务模式。
  • 是的,你是对的。我必须承认,我并不完全了解适当的工作单元实施试图在此之外完成什么。我从经验中知道的一件事是,我宁愿进行微交易,然后长时间保持对象的连接。我只是获取一个对象,创建一个 DTO 并将其移动到服务上。
【解决方案2】:

好的,这是我想出但尚未尝试过的解决方案。它有点简单,实际上可以围绕 MEF 工作,但并没有真正破坏它,至少在我的情况下不是。

在IRepository类中添加如下方法:

void SetContext(IDbContext context);

或者更好

IDbContext context { set; }

在工厂里:

public class RepositoryFactory
{
    private readonly CompositionContainer _container;

    [Import(RequiredCreationPolicy=CreationPolicy.NonShared)]
    private readonly IDbContext _context;

    public IRepository<T> CreateRepository<T>() where T : class, IEntity
    {
        IRepository<T> repo = _container.GetExportedValue<EntityRepository<T>>();
        repo.context = _context;

        return repo;
    }
}

其余的应该是不言自明的:

public  class   EntityRepository<T> :   IRepository<T>  where   T   :   class,  IEntity
{
    protected   IDbContext  _context;

    IDbContext  context
    {
        set {   _context    =   value;  }
    }

    public  virtual IQueryable<T>   GetQuery()
    {
        return  _context.Set<T>();
    }

    public  virtual T   GetById(Guid    id)
    {
        return  _context.Set<T>().Find(id);
    }

    public  virtual void    SaveOrUpdate(T  entity)
    {
        if  (_context.Set<T>().Find(entity.Id)  ==  null)
        {
            _context.Set<T>().Add(entity);
        }

        _context.SaveChanges();
    }

    public  virtual void    Delete(T    entity)
    {
        _context.Set<T>().Remove(entity);

        _context.SaveChanges();
    }
}

如果您以与我相同的方式使用它,我真的看不出这个实现有什么问题。工厂负责创建类,因此它可以负责设置上下文。 CreationPolicy 应确保每个工厂都获得自己的 DbContext 实例,然后将其委托给自己的存储库,以便它们共享上下文。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-29
    • 2015-12-17
    • 1970-01-01
    • 2020-06-22
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多