Нужен пример для Entity Framework при регистрации саговых репозиториев с помощью autofac

В документации masstransit есть пример для NHiberbate, есть ли у кого-нибудь такой же пример, но с использованием структуры сущностей (SagaDbContextFactory,SagaDbContext) вместо NHibernate

// не забудьте зарегистрировать репозитории саги (пример для NHibernate)
var mappings = mappingsAssembly
    .GetTypes()
    .Where(t => t.BaseType!= Null && t.BaseType.IsGenericType &&
        (t.BaseType.GetGenericTypeDefinition() == typeof(SagaClassMapping<>) ||
        t.BaseType.GetGenericTypeDefinition() == typeof(ClassMapping<>)))
    .ToArray();
builder.Register(c => new SqlServerSessionFactoryProvider(connString, mappings).GetSessionFactory())
    .Как  ()
    .SingleInstance();
builder.RegisterGeneric(TypeOf(NHibernateSagaRepository<>))
    .Как (TypeOf(ISagaRepository<>));

2 ответа

Я зарегистрировал мой, как это:

builder.RegisterAssemblyTypes(typeof(SomeType).Assembly).AsImplementedInterfaces().AsSelf(); 

builder.RegisterGeneric(typeof(SagaRepository<,>)).As(typeof(ISagaRepository<,>));

builder.RegisterGeneric(typeof(SagaDbContext<,>));

А затем реализовал интерфейс SagaRepository:

internal class SagaRepository<TSaga, TSagaClassMapping> : EntityFrameworkSagaRepository<TSaga>, ISagaRepository<TSaga, TSagaClassMapping>
    where TSaga : class, ISaga where TSagaClassMapping : SagaClassMapping<TSaga>, new()
{
    public SagaRepository(
        IWorkerConfiguration workerConfiguration)
        : base(() => new SagaDbContext<TSaga, TSagaClassMapping>(workerConfiguration.ConnectionStrings["SagaRepository"]))
    {
    }
}

Для сопоставлений я использую базовый класс:

internal abstract class BaseInstanceStateMap<TInstance> : SagaClassMapping<TInstance>, IInstanceStateMap<TInstance> where TInstance : BaseSagaInstance
{
    protected BaseInstanceStateMap()
    {
        this.Property(x => x.CorrelationId);
        this.Property(x => x.CurrentState).HasMaxLength(64);

        this.Property(x => x.Initiated).HasColumnType("datetime2").IsRequired();
        this.Property(x => x.Created).HasColumnType("datetime2").IsRequired();
        this.Property(x => x.StateChanged).HasColumnType("datetime2").IsOptional();
    }
}

Который я затем наследую для каждого из моих отображений:

internal class ProductIndexingStateMap : BaseInstanceStateMap<ProductIndexingSagaInstance>
{
    public ProductIndexingStateMap()
    {
        this.Property(x => x.ProductId);
        this.Property(x => x.ProductCorrelation);
        this.Property(x => x.EncryptedConnectionString);
    }
}

Вы действительно можете зарегистрироваться EntityFrameworkSagaRepository<T> как общий, но вам потребуется зарегистрировать один DbContext, Если вы используете SagaDbContext - в вашем приложении не может быть более одной саги. Единственный путь - привязать реализацию собственного репозитория и SagaDbContext через параметры универсального типа это то, что делает @slinzerthegod в своем примере.

Вы также можете создать свой собственный контекст, который будет регистрировать все типы. Например:

public class AssemblyScanningSagaDbContext : DbContext
{
    readonly Assembly _mappingAssembly;

    public AssemblyScanningSagaDbContext(Assembly mappingAssembly, string nameOrConnectionString)
        : base(nameOrConnectionString)
    {
        _mappingAssembly = mappingAssembly;
    }

    public AssemblyScanningSagaDbContext(Assembly mappingAssembly, ObjectContext objectContext, bool dbContextOwnsObjectContext)
        : base(objectContext, dbContextOwnsObjectContext)
    {
        _mappingAssembly = mappingAssembly;
    }

    public AssemblyScanningSagaDbContext(Assembly mappingAssembly, DbConnection existingConnection, bool contextOwnsConnection)
        : base(existingConnection, contextOwnsConnection)
    {
        _mappingAssembly = mappingAssembly;
    }

    public AssemblyScanningSagaDbContext(Assembly mappingAssembly, string nameOrConnectionString, DbCompiledModel model)
        : base(nameOrConnectionString, model)
    {
        _mappingAssembly = mappingAssembly;
    }

    public AssemblyScanningSagaDbContext(Assembly mappingAssembly, DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection)
        : base(existingConnection, model, contextOwnsConnection)
    {
        _mappingAssembly = mappingAssembly;
    }

    protected AssemblyScanningSagaDbContext(Assembly mappingAssembly)
    {
        _mappingAssembly = mappingAssembly;
    }

    protected AssemblyScanningSagaDbContext(Assembly mappingAssembly, DbCompiledModel model)
        : base(model)
    {
        _mappingAssembly = mappingAssembly;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) =>
        modelBuilder.Configurations.AddFromAssembly(_mappingAssembly);
}

Если у вас есть такой класс, вы можете сделать следующее:

builder.Register(c => new AssemblyScanningSagaDbContext(typeof(MySagaMapping).Assembly,
    connectionString).As<DbContext>();
builder.RegisterGeneric(typeof(EntityFrameworkSagaRepository<>))
    .As(typeof(ISagaRepository<>))
    .SingleInstance();
builder.RegisterStateMachineSagas(typeof(MySaga).Assembly);

Autofac может автоматически создать делегат фабрики и внедрить его в конструктор хранилища.

Вот контекст сканирования как суть.

Другие вопросы по тегам