Set Value before save

社会主义新天地 提交于 2020-01-13 04:26:28

问题


I was wondering if there is any way to set a value to an entity onsave?
Because I'm working on a multi tenant web application and I would like to set the the current tenant ID (through simple DI service).

I tried using HasDefaultValue() in Fluent API, however this will try to convert to a SQL function. So this doesn't work for me.

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

Any suggestions are greatly appreciated.


回答1:


You could override the DbContext.SaveChanges() method and iterate the ChangeTracker entries:

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();
}

Of course, this needs the tenant provider to be injected into your context.




回答2:


EF Core value generation on add with custom ValueGenerator

Generates values for properties when an entity is added to a context.

could be utilized to assign TenantId to the new entities. Inside the Next method you could obtain the TenantId from the context (or some service).

Taking your sample, the value generator could be a nested class inside your DbContext like this:

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();
}

The all you need is to assign the generator to TenantId property using some of the HasValueGenerator fluent API.

The only problem is that by design the value generators are called only if the property does not have explicitly set value (for int property - if the value is 0).

So the better approach it to abstract (and fully control) the TenantId property by removing it from entity models and replacing it with shadow property.

Hence my suggestion is, remove the TenantId from entity classes and call the following method inside your OnModelCreating for each entity that needs TenantId column:

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());
    });
}


来源:https://stackoverflow.com/questions/52954659/set-value-before-save

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!