我想知道是否有任何方法可以为实体保存设置值?
因为我正在处理多租户Web应用程序,所以我想设置当前的租户ID(通过简单的DI服务)。
我尝试在Fluent API中使用HasDefaultValue()
,但是这将尝试转换为SQL函数。所以这对我不起作用。
builder.Entity<Order>( )
.HasQueryFilter(p => p.TenantId == _tenantProvider.GetTenantId())
.Property(p => p.TenantId)
.HasDefaultValue(_tenantProvider.GetTenantId());
任何建议都将不胜感激。
答案 0 :(得分: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();
}
当然,这需要将租户提供者注入您的上下文中。
答案 1 :(得分:2)
如果您使用的是 EF Core 5+,则可以选择使用 SavingChanges
事件。这将允许您为 SaveChanges
和 SaveChangesAsync
设置自定义逻辑,而无需覆盖这两个方法。
示例:
public MyDbContext(DbContextOptions<MyDbContext> dbContextOptions, ITenantProvider tenantProvider) : base(dbContextOptions)
{
SavingChanges += (sender, args) =>
{
foreach (var orderEntity in ChangeTracker.Entries<Order>())
{
if (orderEntity.State == EntityState.Added)
{
orderEntity.Entity.TenantId = tenantProvider.GetTenantId();
}
}
};
}
答案 2 :(得分:1)
具有自定义value generation on add的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();
}
您需要做的就是使用一些HasValueGenerator流利的API将生成器分配给TenantId
属性。
唯一的问题是,根据设计,只有在属性没有显式设置值的情况下才调用值生成器(对于int
属性-如果值是0
)。
因此,更好的方法是通过从实体模型中删除TenantId
属性并将其替换为shadow property来抽象(并完全控制)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());
});
}
列的每个实体调用以下方法:
32