1

我想将我的实体框架上下文绑定到每个 NServicebus 消息的范围内。下面的代码会成功地做到这一点吗?

Bind<IDbContext>().To<MyContext>()
    .InScope(x => x.Kernel.Get<IBus>().CurrentMessageContext.Id);

背景

我有一个 NServicebus 服务,它有几个 IMessageHandlers 从 MSMQ 队列中读取 IEvents。

每个处理程序通过位于实体框架上下文上的特定 IRepository 转换消息并将其保存到 MS SQL 数据库。

每个处理程序所需的存储库通过 ninject 使用 NServicebus.ObjectBuilder.Ninject 注入

public class Product
{
    public string Code { get; set; }
    public Category Category { get; set; }
}

public class Category
{
    public string Code { get; set; }
}

public class SampleContext : IDbContext
{
    IDbSet<Product> Products { get; }
    IDbSet<Category> Categories{ get; }
}

public class ProductRepository : IProductRepository
{
    private IDbContext _context;
    public ProductRepository(IDbContext ctx) { _context = ctx; }

    public void Add(Product p)
    {
        _context.Products.Add(p);
        _context.SaveChanges();
    }
}

public class CategoryRepository : ICategoryRepository
{
    private IDbContext _context;
    public CategoryRepository (IDbContext ctx) { _context = ctx; }

    public Category GetByCode(string code)
    {
        return _context.Categories.FirstOrDefault(x => x.Code == code);
    }
}

public class AddProductMessageHandler : IMessageHandler<IAddProductEvent>
{
    private IProductRepository _products;
    private ICategoryRepository _categories;
    public AddProductMessageHandler(IProductRepository p, ICategoryRepository c)
    {
        _products = p;
        _categories = c;
    }

    public void Handle(IAddProductEvent e)
    {
        var p = new Product();
        p.Code = e.ProductCode;
        p.Category = _categories.GetByCode(e.CategoryCode);
        _products.Add(p);
    }
}

问题

如果 EF 上下文绑定在瞬态范围内(默认),则处理程序中的每个绑定存储库都有它自己的上下文实例。

Bind<IDbContext>().To<SampleContext>();

如果我从一个存储库加载一个对象然后通过另一个存储库保存它,这会导致问题。

同样,如果它绑定在 Singleton 范围内,则所有存储库都使用相同的上下文,但随后它会慢慢填满跟踪的更改并占用我所有的 ram(并且启动速度越来越慢)。

Bind<IDbContext>().To<SampleContext>().InSingletonScope();

问题

理想情况下,我希望每个消息处理程序都有 1 个 EF 上下文,所有必需的存储库(该处理程序的)都使用它来加载和保存实体。

将上下文限定为当前消息 Id 属性是一种安全/可靠/好方法吗?

Bind<IDbContext>().To<SampleContext>()
    .InScope(x => x.Kernel.Get<IBus>().CurrentMessageContext.Id);
4

2 回答 2

2

请参阅我的博文,其中描述了 NSB 4.0 之外的范围

http://www.planetgeek.ch/2013/01/16/nservicebus-unitofworkscope-with-ninject/

如果您有 3.0,您可以查看当前的开发分支并将扩展方法移植到您的代码中。您只需更改范围名称。

于 2013-02-20T11:23:35.740 回答
0

我不熟悉 EF Context,所以如果下面的答案没有任何意义,请忽略。

如果 EF Context 类似于 NH ISession,那么我认为更好的选择是使用与NH implementation相同的 UoW 。您可以在此处
阅读有关 UoW的更多信息。

于 2013-02-19T22:34:07.143 回答