我们正在尝试在基于Web API的应用程序中实现多租户架构。我们在SQL Server中使用RLS,Subscription_Id
是给每个订阅者的内容。我们在SQL Server中设置了Subscription_Id
的默认值,所以当我调用db.SaveChanges()
时,我只想忽略从API进入SQL Server的Subscription_Id
。
我尝试在Subscription_Id
覆盖方法中设置SaveChanges()
的值,但卡在此处。
public override int SaveChanges()
{
var objectType = selectedEntity.CurrentValues.ToObject();
Guid value = new Guid("54E720FC-616B-44C6-8485-5F2185FD7B4C");
PropertyInfo propertyInfo =
objectType.GetType().GetProperty("Subscription_Id");
ChangeTracker.Entries().FirstOrDefault()
.CurrentValues.ToObject().GetType()
.GetProperty("Subscription_Id")
.SetValue(objectType, Convert.ChangeType(value, propertyInfo.PropertyType), null);
return base.SaveChanges();
}
答案 0 :(得分:0)
我的建议是,您不应修改SaveChanges()
代码。
使用RLS的推荐方法是使TenantId
列对您的EF模型和代码透明,这样您就不需要在实体中定义租户ID或导航属性。这样,您就不需要更改SaveChanges()
代码,或者在打开数据库连接时,在代码中的任何位置显式管理和设置Subscription_Id
值。
您需要做的是在数据库的Subscription_Id
列中手动设置默认值约束,默认值基于当前会话Subscription_Id
参数。插入记录时将设置该值,并隐式用于过滤数据库级别的任何后续查询和命令。
如果是新列:
ALTER TABLE SomeEntityTable ADD Subscription_Id nvarchar(128)
DEFAULT CAST(SESSION_CONTEXT(N'UserId') AS nvarchar(128))
如果是现有专栏:
ALTER TABLE SomeEntityTable
ADD DEFAULT CAST(SESSION_CONTEXT(N'UserId') AS nvarchar(128)
FOR Subscription_Id
如果列具有先前不同的DEFAULT
值,则最好还删除其关联的过时DEFAULT
约束。有关更新现有列中默认值的详细信息,请参见here。
这些列不应包含在您的模型中。您不应该在实体类中拥有它们的属性。如果您使用的是Database First,则应确保在从数据库更新模型时排除/忽略这些列。
如果您使用EF Code First,如何执行此操作:在使用AlterColumn
生成代码迁移后,您可以在代码迁移中手动包含CreateColumn
(或Add-Migration
)条指令。为每个实体表执行此操作:
public override void Up()
{
AlterColumn("dbo.SomeEntityTable", "Subscription_Id",
c => c.String(
nullable: false,
maxLength: 128,
defaultValueSql: "CAST(SESSION_CONTEXT(N'UserId') AS nvarchar(128))"));
}
(最好还添加一个删除列的Down()
方法。)
警告:运行此迁移时请务必小心,如果表中的现有记录的列值为Subscription_Id
空(或者您要添加新的Subscription_Id
}列到已有记录的表)。空列将填充正在执行迁移的连接中Subscription_Id
的值,这可能是错误的(您可能不希望所有现有记录与该特定订阅相关联) )。在这种情况下,您可能希望在UPDATE
方法中使用Subscription_Id
方法,在Up()
方法中包含明确的Sql()
指令。像这样:
Sql("UPDATE SomeEntitiesTable SET Subscription_Id= '19bc9b0d-28dd-4510-bd5e-d6b6d445f511' WHERE Id IN (1, 2, 5)");
使用Code First,您还应该从模型类中删除Subscription_Id
属性。如果您不能在Ignore()
列的配置代码中添加明确的Subscription_Id
说明,那么您在EF映射中不需要它们。
注意:我在此假设您在数据库中创建了一个使用UserId
中的SESSION_CONTEXT
参数的RLS策略,并且您的应用程序代码在打开数据库连接时设置了该值,通过DbConnectionInterceptor
或类似的东西。
This page包含更多信息。