Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save BrutalSimplicity/00ed60869f49b19ac630485f2a3c6287 to your computer and use it in GitHub Desktop.
Save BrutalSimplicity/00ed60869f49b19ac630485f2a3c6287 to your computer and use it in GitHub Desktop.
transaction repo brainstorm
// this is only a marker for resolving the TransactionalQueryManager
public interface ITransactionRepository
{
}
public class ProductRepository : IProductRepository, ITransactionRepository
{
}
// remove IProductTransactionRepository and implementations
// remove ProductTransactionFactory
public class TransactionScopedRepositoryFactory : ITransactionScopedRepository
{
IEnumerable<ITransactionRepository> _repositories;
// when passed an Enumerable, Autofac will automatically
// give you all implementations registered to that interface
public TransactionScopedRepositoryFactory(
IEnumerable<ITransactionRepository> repositories
{
_repositories = repositories;
}
public void Create<T>()
{
return repositories.FirstOrDefault(r => r.GetType() == typeof(T));
}
}
// in DefaultAutoBuilder.cs handle binding all of the repositories that need the
// transactional query manager
// all of these should be resolved with the same `TransactionalQueryManager`
// instance during the scope of a job, so their operations should be included
// in the transaction ** I think :) **
this.RegisterType<TransactionalQueryManager>().As<ITransactionalQueryManager>().InstancePerLifetimeScope();
this.RegisterType<ProductRepository>().As<ITransactionRepository>().InstancePerLifetimeScope()
.WithParameters(new[] {
new Autofac.Core.ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(IQueryManager),
(pi, ctx) => ctx.Resolve<ITransactionalQueryManager>()
)
});
this.RegisterType<UpdateProductItemRepository>().As<ITransactionRepository>().InstancePerLifetimeScope()
.WithParameters(new[] {
new Autofac.Core.ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(IQueryManager),
(pi, ctx) => ctx.Resolve<ITransactionalQueryManager>()
)
});
// usage in service
public class ProductUpdateJob
{
ITransactinoalQueryManager _manager;
IUpdateProductItemRepository _updateRepo;
IProductRepository _productRepo;
public ProductUpdateJob(
ITransactionalQueryManager manager,
IProductRepository productRepo,
IUpdateProductItemRepository updateRepo
{
_manager = manager;
_productRepo = productRepo;
_updateRepo = updateRepo;
}
public void ProcessProducts(int limit)
{
var items = _updateRepo.GetNextBatchForUpdate(limit);
var productsForUpdate = _productRepo.GetWhere("select * from products where pid = any(@pids) for update",
new { pids = items.Select(p => p.PID.Value).ToArray() });
// join back with items somehow
foreach (var product in productsForUpdate)
{
DoUpdate(product);
DoRemove(product);
}
Update(items);
_productRepo.Save(productsForUpdate);
_updateRepo.Save(items)
// this effectively commits the transaction across all of the repositories
_manager.Commit();
}
}
public TestClass
{
public void Transaction_scope_should_be_shared()
{
var container = ShopSavvyDependencyModule.LoadBindings(() => builder
{
builder.RegisterType<MyOwnTransactionQueryManager>().As<ITransactionalQueryManager>();
});
var transactionManager = (MyOwnTransactionQueryManager)context.Resolve<ITransactionalQueryManager>();
var repos = context.Resolve<IEnumerable<ITransactionScopedRepository>>();
// now check that the instance count remains the same
Assert.AreEqual(1, transactionManager.InstanceCount);
}
}
public class MyOwnTransactionQueryManager : ITransactionalQueryManager
{
public static InstanceCount;
public MyOwnTransactionQueryManager()
{
InstanceCount++;
}
// implement interface
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment