내 최근 프로젝트에 CQRS 패턴을 사용하고, 및 사용 EF 코드를 사용하여 일반 CommandHandler 각 모듈마다 다른 UnitOfWorks 등록, 그래서 삽입/업데이트 할 몇 가지 일반적인 CommandHandlers
정의/삭제 :내 DAL 먼저 structuremap
public class InsertCommandHandler<TEntity> : ICommandHandler<InsertCommandParameter<TEntity>>
where TEntity : BaseEntity, IAggregateRoot<TEntity>, new()
{
private readonly IUnitOfWork _uow;
public InsertCommandHandler(IUnitOfWork uow)
{
_uow = uow;
}
public void Handle(InsertCommandParameter<TEntity> parameter)
{
var entity = parameter.Entity;
_uow.Repository<TEntity>().Add(entity);
}
}
public interface ICommandParameter
{
}
public abstract class BaseEntityCommandParameter<T> : ICommandParameter
where T : BaseEntity, new()
{
public T Entity { get; set; }
protected BaseEntityCommandParameter()
{
Entity = new T();
}
}
public class InsertCommandParameter<T> : BaseEntityCommandParameter<T> where T : class, new()
{
}
은 내가 InsertCommandHandler
생성자에 IUnitOfWork
을 주입.
public interface IUnitOfWork : IDisposable
{
IRepository<T> Repository<T>() where T : BaseEntity, IAggregateRoot<T>,new();
void Commit();
}
나는 나의 IoC Container
로 Structuremap 3
을 사용, 그래서 정의 된 변환 다음 (custom registration conventions for partially closed types 사용) 각 BaseEntity
유형 ICommandHandler
의 해결을 위해 :
public class CRUDCommandRegistrationConvention : StructureMap.Graph.IRegistrationConvention
{
private static readonly
Type _openHandlerInterfaceType = typeof(ICommandHandler<>);
private static readonly
Type _openInsertCommandType = typeof(InsertCommandParameter<>);
private static readonly
Type _openInsertCommandHandlerType = typeof(InsertCommandHandler<>);
private static readonly
Type _openUpdateCommandType = typeof(UpdateCommandParameter<>);
private static readonly
Type _openUpdateCommandHandlerType = typeof(UpdateCommandHandler<>);
private static readonly
Type _openDeleteCommandType = typeof(DeleteCommandParameter<>);
private static readonly
Type _openDeleteCommandHandlerType = typeof(DeleteCommandHandler<>);
public void Process(Type type, Registry registry)
{
if (!type.IsAbstract && typeof(BaseEntity).IsAssignableFrom(type))
if (type.GetInterfaces()
.Any(x => x.IsGenericType && x.GetGenericTypeDefinition()
== typeof(IAggregateRoot<>)))
{
Type closedInsertCommandType = _openInsertCommandType.MakeGenericType(type);
Type closedInsertCommandHandlerType = _openInsertCommandHandlerType.MakeGenericType(type);
Type closedUpdateCommandType = _openUpdateCommandType.MakeGenericType(type);
Type closedUpdateCommandHandlerType = _openUpdateCommandHandlerType.MakeGenericType(type);
Type closedDeleteCommandType = _openDeleteCommandType.MakeGenericType(type);
Type closedDeleteCommandHandlerType = _openDeleteCommandHandlerType.MakeGenericType(type);
Type insertclosedHandlerInterfaceType = _openHandlerInterfaceType.MakeGenericType(closedInsertCommandType);
Type updateclosedHandlerInterfaceType = _openHandlerInterfaceType.MakeGenericType(closedUpdateCommandType);
Type deleteclosedHandlerInterfaceType = _openHandlerInterfaceType.MakeGenericType(closedDeleteCommandType);
registry.For(insertclosedHandlerInterfaceType).Use(closedInsertCommandHandlerType);
registry.For(updateclosedHandlerInterfaceType).Use(closedUpdateCommandHandlerType);
registry.For(deleteclosedHandlerInterfaceType).Use(closedDeleteCommandHandlerType);
}
}
}
그리고 내 CompositionRoot에서 그것을 사용 :
public static class ApplicationConfiguration
{
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(s =>
{
s.AssemblyContainingType(typeof(ICommandHandler<>));
s.AssemblyContainingType(typeof(Order));
s.AssemblyContainingType(typeof(FindOrderByIdQueryHandler));
s.WithDefaultConventions();
x.For(typeof(IUnitOfWork))
.Use(typeof(EfUnitOfWork<SaleDBContext>))
.Named("SaleDBContext")
.SetLifecycleTo((Lifecycles.Singleton));
s.Convention<CRUDCommandRegistrationConvention>();
});
});
return ObjectFactory.Container;
}
public static T Resolve<T>()
{
return ObjectFactory.GetInstance<T>();
}
}
IUnitOfWork
에 대해 EfUnitOfWork<SaleDBContext>
을 등록했지만 내 솔루션 (Bounded context
)에서 각 모듈 당 DbContext
을 분리하여 사용하십시오. 예를 들어 내 판매 모듈에는 DbContext
, HR 모듈에는 DbContext
등이 있으며 위 등록 변환에는 으로 등록 EfUnitOfWork<SaleDBContext>
만 등록하면됩니다.
내가 내 솔루션에서 일부 모듈 (Visual Studio에서 솔루션 폴더)가 각각의 모듈은 3 계층 (3 개 클래스 라이브러리 프로젝트)이 있습니다
: 내 모듈 구조를 다음있다 (예를 들어, 각 모듈은 3 어셈블리가 있습니다)SaleModule:
----Application
----Domain (Entities , ...) //Order, Customer,...
----DAL (DbContext ,...) //SaleDbContext
HRModule:
----Application
----Domain (Entities , ...) // Employee, OrganizationUnit, ...
----DAL (DbContext ,...)//HRDbContext
InfrastructureModule:
----Application (ICommandHandler,IQueryHandler,...)
----Domain
----DAL
InsertCommandHandler<T>
은 인프라 모듈에 넣습니다.
내가 InsertCommanHandler<T>
을 사용할 때 해당 모듈의 DbContext
을 IUnitOfWork
으로 사용하고 싶습니다. 예를 들어 InsertCommandHandler<Order>
은 이고, IUnitOfWork
이고 InsertCommandHandler<Employee>
은 IUnitOfWork
이므로 HRDbContext
을 사용하고 싶습니다.
[업데이트]]
이의 IoC containar이 Consumer2
에 대한 Consumer1
및 HRDbContext
에 대한 SaleDbContext
을 제공해야 cunsumers 코드의 샘플입니다 : 나는 내 조성 루트에 사용하는 것을 할 수있는 방법
public class Consumer1
{
ICommandHandler<InsertCommandParameter<Order>> _insertCommandHandler;
public Consumer1(ICommandHandler<InsertCommandParameter<Order>> insertCommandHandler)
{
_insertCommandHandler = insertCommandHandler;
}
public void DoInsert()
{
var command = new InsertCommandParameter<Order>();
command.Entity = new Order(){
Number = 'ord-01',
// other properties
};
insertCommandHandler.Handle(command); //this query handler should use SaleDbContext
}
}
public class Consumer2
{
ICommandHandler<InsertCommandParameter<Employee>> _insertCommandHandler;
public Consumer2(ICommandHandler<InsertCommandParameter<Employee>> insertCommandHandler)
{
_insertCommandHandler = insertCommandHandler;
}
public void DoInsert()
{
var command = new InsertCommandParameter<Employee>();
command.Entity = new Employee(){
EmployeeNumber = 'Emp1',
// other properties
};
insertCommandHandler.Handle(command); //this query handler should use HRDbContext
}
}
을 StructureMap
?
감사 qujck 난 당신의 솔루션을 사용하는 경우, 그러나, 나는 각 엔티티에 대해 개별적으로 OrderInsertCommandHandler, EmployeeInsertCommandHandler, ...를 정의해야합니다,하지만 난 내 질문에 업데이트 된 내 기관에 대한 일반 InsertCommandHandler을 <>를 사용하려면, PLZ 소비자 클래스를 참조하십시오. – Masoud
@Masoud가 내 업데이트를보고 있습니다.이 기능이 작동합니까? – qujck
나는 그것이 작동한다고 생각하지만 가능한 한 하나의'InsertCommandHandler'클래스로 해결책을 찾고있다. –
Masoud