Entity framework 如何更改DbContext.SaveChanges()的条目值
我们正在尝试在基于Web API的应用程序中实现多租户体系结构。我们在SQL Server中使用RLS,Entity framework 如何更改DbContext.SaveChanges()的条目值,entity-framework,asp.net-web-api,db-first,Entity Framework,Asp.net Web Api,Db First,我们正在尝试在基于Web API的应用程序中实现多租户体系结构。我们在SQL Server中使用RLS,Subscription\u Id是提供给每个订阅者的内容。我们已经在SQL Server中为Subscription\u Id设置了默认值,因此当我调用db.SaveChanges()时,我只想忽略从API进入SQL Server的订阅Id。 我尝试在SaveChanges()override方法中设置Subscription\u Id的值,但在这里卡住了 public override i
Subscription\u Id
是提供给每个订阅者的内容。我们已经在SQL Server中为Subscription\u Id
设置了默认值,因此当我调用db.SaveChanges()
时,我只想忽略从API进入SQL Server的订阅Id
。我尝试在
SaveChanges()
override方法中设置Subscription\u Id
的值,但在这里卡住了
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();
}
我的建议是,您不应该为此修改
SaveChanges()
代码
建议使用RLS的方法是使TenantId
列对EF模型和代码透明,因此您不需要在实体中定义租户ID或导航属性。这样,您就不需要更改SaveChanges()
代码,也不需要显式地管理和设置代码中的Subscription\u Id
值,打开DB连接时除外
您需要做的是在数据库中的Subscription\u Id
列中手动设置默认值约束,默认值基于当前会话Subscription\u 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
约束。可以找到有关更新现有列中默认值的更多信息
这些列不应包含在模型中。在实体类中不应该有它们的属性。如果您首先使用数据库,则应确保在从数据库更新模型时排除/忽略这些列 如果您首先使用EF代码,如何执行此操作:使用
添加迁移
生成代码迁移后,您可以在代码迁移中手动包含AlterColumn
(或CreateColumn
)指令。对每个实体表执行此操作:
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\u Id
列值的记录(或者向已有记录的表中添加新的Subscription\u Id
列),则运行此迁移时要小心。空列将填充执行迁移的连接中的订阅\u Id
的值,这可能是错误的(您可能不希望所有现有记录都与该特定订阅关联)。在这种情况下,您可能希望使用Sql()
方法在Up()
方法中包含带有正确Subscription\u Id
值的显式UPDATE
说明。大概是这样的:
Sql("UPDATE SomeEntitiesTable SET Subscription_Id= '19bc9b0d-28dd-4510-bd5e-d6b6d445f511' WHERE Id IN (1, 2, 5)");
使用“代码优先”,您还应该从模型类中删除Subscription\u Id
属性。如果不能,至少在配置代码中为Subscription\u Id
列添加显式Ignore()
指令,您不希望它们出现在EF映射中
注意:我在这里假设您在数据库中创建了一个RLS策略,该策略在会话\u上下文中使用用户ID
参数,并且您的应用程序代码在打开数据库连接时通过DbConnectionInterceptor
或类似的东西设置该值
包含更多信息。为什么要更改或覆盖订阅Id?我认为这是一个主键/唯一键。否订阅id是针对订阅服务器的,因此与订阅服务器相关的所有数据都与订阅服务器id一起保存为什么要在savechanges()中设置订阅id的值?因为我在sql中使用行级安全性,并且我已经设置了subscriptionid以进行检查,并将subscriptionid的默认值设置为当前上下文值,但实体框架将subscriptionid发送为null,我只想忽略订阅id或发送savechanges上的值,因为所有表都会有该列“这些列不应包含在您的模型中。在实体类中不应该有它们的属性。如果您首先使用数据库,则应确保在从数据库更新模型时排除/忽略这些列。“如何排除Database first EF中的列。我已经设置了订阅id默认值。我对Database first不太熟悉。从注释中可以看出,您可以从edmx中的类模型中删除属性,并且在下次更新模型时不会重新生成这些属性,因为这些列仍然是我的n存储模型,因此EF不认为它们是添加到类模型中的新列。