Для такого динамического sql я обычно рекомендую использовать Табличный параметр .
Требуется немного настройки: вам нужно создать определяемый пользователем тип в БД для хранения значений, но это довольно тривиальная операция:
CREATE TYPE PrimaryKeyType AS TABLE ( VALUE INT NOT NULL );
Обычно мы используем их вместе с хранимыми процедурами:
CREATE PROCEDURE dbo.getFamily(@PrimaryKeys PrimaryKeyType READONLY)
AS
SELECT FamilyID, FullName, Alias
FROM TABLE (nolock) INNER JOIN @PrimaryKeys ON TABLE.FamilyID = @PrimaryKeys.Value
GO
Однако вы также можете использовать встроенный SQL, если хотите.
Присвоить значения хранимому параметру proc или inline довольно просто, но есть одна ошибка (более позднее):
public static void AssignValuesToPKTableTypeParameter(DbParameter parameter, ICollection<int> primaryKeys)
{
// Exceptions are handled by the caller
var sqlParameter = parameter as SqlParameter;
if (sqlParameter != null && sqlParameter.SqlDbType == SqlDbType.Structured)
{
// The type name may look like DatabaseName.dbo.PrimaryKeyType,
// so remove the database name if it is present
var parts = sqlParameter.TypeName.Split('.');
if (parts.Length == 3)
{
sqlParameter.TypeName = parts[1] + "." + parts[2];
}
}
if (primaryKeys == null)
{
primaryKeys = new List<int>();
}
var table = new DataTable();
table.Columns.Add("Value", typeof(int));
foreach (var wPrimaryKey in primaryKeys)
{
table.Rows.Add(wPrimaryKey);
}
parameter.Value = table;
}
Здесь нужно следить за именованием параметра. См. Код в методе выше, который удаляет имя базы данных для решения этой проблемы.
Если у вас динамический SQL, вы можете сгенерировать правильный параметр, используя следующий метод:
public static SqlParameter CreateTableValuedParameter(string typeName, string parameterName)
{
// Exceptions are handled by the caller
var oParameter = new SqlParameter();
oParameter.ParameterName = parameterName;
oParameter.SqlDbType = SqlDbType.Structured;
oParameter.TypeName = typeName;
return oParameter;
}
Где typeName
- имя вашего типа в БД.