我想将我的实体框架上下文绑定到每个 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);