.NET 개발의 경우 ORM의 99%가 Entity Framework를 사용합니다. Entity Framework에서 제공하는 DbContext는 Unit of Work 및 Repository 패턴을 위해 생성되었지만 비즈니스 프로젝트는 인프라에 의존하기 때문에 비즈니스 프로젝트에서 DbContext를 사용하는 것은 좋지 않습니다. 결과적으로 별도의 리포지토리와 UnitOfWork 인터페이스/클래스가 개발 및 개발되는데 이는 일반적으로 번거로운 작업이 아닙니다. 엔터티별로 리포지토리 인터페이스가 정의된 후 구현해야 하며 단위 테스트를 개별적으로 작성하는 것은 비효율의 끝을 보여주는 프로세스라고 할 수 있습니다. 저는 예전에 Java를 사용할 때 JPA를 사용했는데 인터페이스를 지정하여 구현 클래스 없이 바로 사용할 수 있다는 생각에 주목하고 오픈소스 프로젝트를 nuget에 업로드했습니다.
아이디어는 간단합니다. UnitOfWork 인터페이스가 삽입되면 주어진 인터페이스를 상속하는 모든 인터페이스가 발견되고 Interceptor 및 Refection을 사용하여 인스턴스가 생성되며 해당 인스턴스는 요청 시 반환됩니다.
아래와 같이 All Assemblies에서 내가 정의한 IEpaRepository를 상속하는 모든 인터페이스를 찾고 Castle의 ProxyGenerator로 생성한 인터페이스를 저장합니다.
AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
.Where(p => p.IsInterface && p.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEpaRepository<,>)))
.ToList().ForEach(c =>
{
var proxy = _proxyGenerator.CreateInterfaceProxyWithoutTarget(c, new EpaRepositoryInterceptor(_dbContext));
if (!_repositories.ContainsKey(c))
{
_repositories.Add(c, proxy);
}
});
EpaRepositoryInterceptor는 Refection을 사용하여 인스턴스를 생성합니다.
/// <summary>
/// An interceptor class to create an instance for any repository interface inheriting <see cref="IEpaRepository{TEntity,TKey}"/>
/// </summary>
internal class EpaRepositoryInterceptor : IInterceptor
{
private readonly IEpaDbContext _dbContext;
public EpaRepositoryInterceptor(IEpaDbContext dbContext)
{
_dbContext = dbContext;
}
/// <inheritdoc />
public void Intercept(IInvocation invocation)
{
var args = invocation.Method.DeclaringType?.GenericTypeArguments;
if (args is not { Length: 2 })
{
throw new InvalidOperationException("The interface should have two generic types, Entity and Key.");
}
var type = typeof(EpaRepository<,>).MakeGenericType(args(0), args(1));
var instance = Activator.CreateInstance(type, _dbContext);
var method = instance?.GetType().GetMethod(invocation.Method.Name);
var resultSet = method?.Invoke(instance, invocation.Arguments);
invocation.ReturnValue = resultSet;
}
}
이와 같은 인스턴스를 만들고 모든 요청에서 해당 가상 인스턴스를 반환하면 IOrderRepository를 정의할 필요가 없고 OrderRepository를 구현해야 하므로 생산성이 기하급수적으로 증가할 수 있습니다.
3년전쯤 비슷한 오픈소스를 만들때 제약이 너무 많았는데 이번 새버전은 정말 깔끔하고 심플하고 기존 소스의 변경이 거의 없어서 매우 만족합니다.
너겟에 대한 더 많은 예제와 WIKI…
https://www.nuget.org/packages/EntityFrameworkCore.PersistenceApi/
EntityFrameworkCore.PersistenceApi 1.0.0
작업 단위와 자동으로 연결된 EntityFramework 리포지토리 패턴.
www.nuget.org