Мне было интересно, есть ли способ установить значение для объекта onsave?
Потому что я работаю над мультитенантным веб-приложением и хотел бы установить текущий идентификатор клиента (с помощью простой службы DI).

Я пробовал использовать HasDefaultValue() в Fluent API, однако он попытается преобразовать его в функцию SQL. Так что у меня это не работает.

builder.Entity<Order>( )
    .HasQueryFilter(p => p.TenantId == _tenantProvider.GetTenantId())
    .Property(p => p.TenantId)
    .HasDefaultValue(_tenantProvider.GetTenantId());

Любые предложения с благодарностью.

3
matt350 23 Окт 2018 в 20:24

2 ответа

Лучший ответ

Вы можете переопределить DbContext. SaveChanges () и перебрать записи ChangeTracker:

public override int SaveChanges()
{
    foreach (var entityEntry in ChangeTracker.Entries()) // Iterate all made changes
    {
        if (entityEntry.Entity is Order order)
        {
            if (entityEntry.State == EntityState.Added) // If you want to update TenantId when Order is added
            {
                order.TenantId = _tenantProvider.GetTenantId();
            }
            else if (entityEntry.State == EntityState.Modified) // If you want to update TenantId when Order is modified
            {
                order.TenantId = _tenantProvider.GetTenantId();
            }
        }
    }
    return base.SaveChanges();
}

Конечно, для этого необходимо, чтобы провайдер арендатора был внедрен в ваш контекст.

3
kaffekopp 23 Окт 2018 в 17:31

EF Core создание значения при добавлении с настраиваемым ValueGenerator

Создает значения для свойств при добавлении сущности в контекст.

Можно использовать для присвоения TenantId новым объектам. Внутри метода Next вы можете получить TenantId из контекста (или какой-либо службы).

Взяв ваш образец, генератор значений может быть вложенным классом внутри вашего DbContext следующим образом:

class TenantIdValueGenerator : ValueGenerator<int>
{
    public override bool GeneratesTemporaryValues => false;
    public override int Next(EntityEntry entry) => GetTenantId(entry.Context);
    int GetTenantId(DbContext context) => ((YourDbContext)context)._tenantProvider.GetTenantId();
}

Все, что вам нужно, это назначить генератор свойству TenantId, используя некоторые из HasValueGenerator свободный API.

Единственная проблема заключается в том, что по замыслу генераторы значений вызываются только в том случае, если свойство не имеет явно установленного значения (для свойства int - если значение равно 0).

Поэтому лучше подойти к нему, чтобы абстрагироваться (и полностью контролировать) свойство TenantId, удалив его из моделей сущностей и заменив на свойство shadow.

Поэтому я предлагаю удалить TenantId из классов сущностей и вызвать следующий метод внутри вашего OnModelCreating для каждой сущности, которой нужен столбец TenantId:

void ConfigureTenant<TEntity>(ModelBuilder modelBuilder) where TEntity : class
{
    modelBuilder.Entity<TEntity>(builder =>
    {
        builder.Property<int>("TenantId")
            .HasValueGenerator<TenantIdValueGenerator>();

        builder.HasQueryFilter(e => EF.Property<int>(e, "TenantId") == _tenantProvider.GetTenantId());
    });
}
1
Ivan Stoev 23 Окт 2018 в 19:44
52954659