如何使用 Table 变量设置 ExecuteSqlCommand
How to set ExecuteSqlCommand with Table variable
我想通过 C# 应用程序 运行 查询。在应用程序之外没有执行此操作的选项。我有以下代码:
var keyGroupsToCleanUp = new List<string>
{
"Address",
"Manufacturer",
"Product",
"Customer",
"Picture",
"Category",
"Vendor",
"SS_A_Attachment",
"SS_A_AttachmentDownload",
"SS_MAP_EntityMapping",
"SS_MAP_EntityWidgetMapping",
};
foreach (var keyGroup in keyGroupsToCleanUp)
{
_databaseFacade.ExecuteSqlCommand($@"
DELETE
FROM GenericAttribute
WHERE KeyGroup = {keyGroup} AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM [{keyGroup}]);
");
}
我想遍历列表中的每个名称,运行 下面的查询针对每个名称。当我尝试这样做时,我收到以下错误:
System.Data.SqlClient.SqlException (0x80131904): Invalid object name '@p1'.
根据我在网上搜集到的信息,这是因为Table名称不能是字符串。您必须声明一个变量并将此变量用于 table 名称。我了解到 Table 变量包含需要声明的列,我感到一阵恐惧。 None 个 table 具有相同的列结构。
我想做的事情可行吗?如果可以,我该怎么做?
GenericAttributes table 是一个很大的 table,由六列组成。
在我加入这个正在使用的项目的时候,已经用到无可替代的地步了。您可以在此处通过将 KeyGroup 指定为数据库 table 来为数据库 table 保存其他数据。我们有一个名为“地址”的 table,我们在地址的 GenericAttributes table 中保存了额外的数据(我知道这没有意义)。这会导致很多问题,因为关系数据库不适用于此。我在上面编写的查询查找现在已分离的 GenericAttributes Table 中的行。例如,EntityId 0 在 Address 中不作为 Id 存在,因此将在此处返回。然后必须删除该行,因为它链接到不存在的 entityId。
这是实现此目的的查询示例:
// Address
_databaseFacade.ExecuteSqlCommand(@"
DELETE
FROM GenericAttribute
WHERE KeyGroup = 'Address' AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM [Address]);
");
我必须这样做 11 table 秒,所以我想让它更容易一些。每个查询都以相同的方式编写。唯一改变的是 KeyGroup 和它寻找的 table。它们将始终具有相同的名称。
这是另一个调用产品的示例。它们是相同的,唯一的区别是 KeyGroup 和 NOT IN 语句中的 Table。
// Product
_databaseFacade.ExecuteSqlCommand(@"
DELETE
FROM GenericAttribute
WHERE KeyGroup = 'Product' AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM Product);
");
尝试以下操作:
foreach (var keyGroup in keyGroupsToCleanUp)
{
var sql = @"DELETE FROM GenericAttribute
WHERE KeyGroup = @Group
AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM @Group)"; // Or [@Group], depends on schema
_databaseFacade.ExecuteSqlCommand(
sql,
new SqlParameter("@Group", keyGroup));
此代码假定您的门面中的 ExecuteSqlCommand
遵循标准的 Microsoft 模式(与 Microsoft 的模式相同)。
据推测,您正在使用 Entity Framework Core。 ExecuteSqlCommand
方法接受 FormattableString
,并将任何占位符转换为命令参数。但是您的占位符似乎是 column/table 名称,不能作为参数传递。
由于还有一个接受 string
的重载,它具有不同的行为,此方法已被标记为已过时,并由 ExecuteSqlInterpolated
和 ExecuteSqlRaw
取代。
假设您的 none 值会受到用户的影响,并且您很高兴不会引入 a SQL Injection vulnerability,您可以改用 ExecuteSqlRaw
:
_databaseFacade.ExecuteSqlRaw($@"
DELETE
FROM GenericAttribute
WHERE KeyGroup = [{keyGroup}] AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM [{keyGroup}]);
");
为了确保没有注入漏洞,可以使用动态SQL和QUOTENAME
_databaseFacade.ExecuteSqlRaw(@"
DECLARE @sql nvarchar(max) = N'
DELETE
FROM GenericAttribute
WHERE KeyGroup = @keyGroup AND [Key] = ''CommonId''
AND EntityId NOT IN (SELECT Id FROM ' + {0} + ');
';
EXEC sp_executesql @sql,
N'@keyGroup nvarchar(100)',
@keyGroup = {0};
", keyGroup);
请注意 ExecuteSqlRaw
将如何插入字符串。 不要自己用$
插值
我想通过 C# 应用程序 运行 查询。在应用程序之外没有执行此操作的选项。我有以下代码:
var keyGroupsToCleanUp = new List<string>
{
"Address",
"Manufacturer",
"Product",
"Customer",
"Picture",
"Category",
"Vendor",
"SS_A_Attachment",
"SS_A_AttachmentDownload",
"SS_MAP_EntityMapping",
"SS_MAP_EntityWidgetMapping",
};
foreach (var keyGroup in keyGroupsToCleanUp)
{
_databaseFacade.ExecuteSqlCommand($@"
DELETE
FROM GenericAttribute
WHERE KeyGroup = {keyGroup} AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM [{keyGroup}]);
");
}
我想遍历列表中的每个名称,运行 下面的查询针对每个名称。当我尝试这样做时,我收到以下错误:
System.Data.SqlClient.SqlException (0x80131904): Invalid object name '@p1'.
根据我在网上搜集到的信息,这是因为Table名称不能是字符串。您必须声明一个变量并将此变量用于 table 名称。我了解到 Table 变量包含需要声明的列,我感到一阵恐惧。 None 个 table 具有相同的列结构。
我想做的事情可行吗?如果可以,我该怎么做?
GenericAttributes table 是一个很大的 table,由六列组成。
在我加入这个正在使用的项目的时候,已经用到无可替代的地步了。您可以在此处通过将 KeyGroup 指定为数据库 table 来为数据库 table 保存其他数据。我们有一个名为“地址”的 table,我们在地址的 GenericAttributes table 中保存了额外的数据(我知道这没有意义)。这会导致很多问题,因为关系数据库不适用于此。我在上面编写的查询查找现在已分离的 GenericAttributes Table 中的行。例如,EntityId 0 在 Address 中不作为 Id 存在,因此将在此处返回。然后必须删除该行,因为它链接到不存在的 entityId。
这是实现此目的的查询示例:
// Address
_databaseFacade.ExecuteSqlCommand(@"
DELETE
FROM GenericAttribute
WHERE KeyGroup = 'Address' AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM [Address]);
");
我必须这样做 11 table 秒,所以我想让它更容易一些。每个查询都以相同的方式编写。唯一改变的是 KeyGroup 和它寻找的 table。它们将始终具有相同的名称。
这是另一个调用产品的示例。它们是相同的,唯一的区别是 KeyGroup 和 NOT IN 语句中的 Table。
// Product
_databaseFacade.ExecuteSqlCommand(@"
DELETE
FROM GenericAttribute
WHERE KeyGroup = 'Product' AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM Product);
");
尝试以下操作:
foreach (var keyGroup in keyGroupsToCleanUp)
{
var sql = @"DELETE FROM GenericAttribute
WHERE KeyGroup = @Group
AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM @Group)"; // Or [@Group], depends on schema
_databaseFacade.ExecuteSqlCommand(
sql,
new SqlParameter("@Group", keyGroup));
此代码假定您的门面中的 ExecuteSqlCommand
遵循标准的 Microsoft 模式(与 Microsoft 的模式相同)。
据推测,您正在使用 Entity Framework Core。 ExecuteSqlCommand
方法接受 FormattableString
,并将任何占位符转换为命令参数。但是您的占位符似乎是 column/table 名称,不能作为参数传递。
由于还有一个接受 string
的重载,它具有不同的行为,此方法已被标记为已过时,并由 ExecuteSqlInterpolated
和 ExecuteSqlRaw
取代。
假设您的 none 值会受到用户的影响,并且您很高兴不会引入 a SQL Injection vulnerability,您可以改用 ExecuteSqlRaw
:
_databaseFacade.ExecuteSqlRaw($@"
DELETE
FROM GenericAttribute
WHERE KeyGroup = [{keyGroup}] AND [Key] = 'CommonId'
AND EntityId NOT IN (SELECT Id FROM [{keyGroup}]);
");
为了确保没有注入漏洞,可以使用动态SQL和QUOTENAME
_databaseFacade.ExecuteSqlRaw(@"
DECLARE @sql nvarchar(max) = N'
DELETE
FROM GenericAttribute
WHERE KeyGroup = @keyGroup AND [Key] = ''CommonId''
AND EntityId NOT IN (SELECT Id FROM ' + {0} + ');
';
EXEC sp_executesql @sql,
N'@keyGroup nvarchar(100)',
@keyGroup = {0};
", keyGroup);
请注意 ExecuteSqlRaw
将如何插入字符串。 不要自己用$