保存前设置值

mat*_*350 7 c# entity-framework-core

我想知道是否有任何方法可以在保存时为实体设置值?
因为我正在开发一个多租户 Web 应用程序,并且我想设置当前租户 ID(通过简单的 DI 服务)。

我尝试在 Fluent API 中使用HasDefaultValue(),但这将尝试转换为 SQL 函数。所以这对我不起作用。

builder.Entity<Order>( )
    .HasQueryFilter(p => p.TenantId == _tenantProvider.GetTenantId())
    .Property(p => p.TenantId)
    .HasDefaultValue(_tenantProvider.GetTenantId());
Run Code Online (Sandbox Code Playgroud)

非常感谢任何建议。

Iva*_*oev 6

使用自定义ValueGenerator添加EF Core值生成

将实体添加到上下文时生成属性值。

可以用来分配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();
}
Run Code Online (Sandbox Code Playgroud)

TenantId您所需要的只是使用一些HasValueGenerator流畅 API将生成器分配给属性。

唯一的问题是,根据设计,仅当属性没有显式设置值时才会调用值生成器(对于int属性 - 如果值为0)。

因此,更好的方法是通过从实体模型中删除属性并用影子属性TenantId替换它来抽象(并完全控制)属性。

因此我的建议是,从实体类中删除并为每个需要列的实体TenantId调用以下方法:OnModelCreatingTenantId

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());
    });
}
Run Code Online (Sandbox Code Playgroud)


kaf*_*opp 5

您可以重写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();
}
Run Code Online (Sandbox Code Playgroud)

当然,这需要将租户提供者注入到您的上下文中。