如何在SqlCommand中传递Dictionary参数

时间:2017-06-06 01:10:39

标签: c# parameters sqlcommand

我有一本字典(Dictionary dic);关键和价值动态变化。

如何使用Insert命令向SQL Server添加记录取决于dic的内容?

例如:

if dic={{"KeyA", "ValueA"}}

然后执行Insert into tblTest(KeyA) values(ValueA)

if dic={{"KeyA", "ValueA"}, {"KeyX", "ValueX"}}

然后执行Insert into tblTest(KeyA,KeyX) values(ValueA,ValueX)

if dic={{"KeyA", "ValueA"}, {"KeyC", "ValueC"}, {"KeyX", "ValueX"}}

然后执行Insert into tblTest(KeyA,KeyC,KeyX) values(ValueA,ValueC,ValueX)

依旧......

有没有人有好主意?

1 个答案:

答案 0 :(得分:2)

你有几个选择。

1。动态SQL

假设您可以使用原始SQL,那么您可以构建一个Dynamic-SQL字符串 - 虽然您可以参数化值,但您无法参数化数据库对象名称(例如列名称),因此存在SQL注入的风险在那里 - 但是使用转义字符'['']'包围所有标识符可以缓解此问题。

但是,幸运的是,值本身仍然可以参数化 - 只需动态添加参数。

我会从你的字典中生成我自己的列名列表,以构建INSERT列表,然后相应地设置参数:

我将如何做到这一点:

var safeNames = dict.Select( pair =>
    new {
        ColumnName = pair.Key.Replace("[", "").Replace("]", ""), // assuming this is sufficient to prevent injection
        Value      = pair.Value
    }
); 

StringBuilder sb = new StringBuilder("INSERT INTO [table] (");

Boolean first = true;
foreach( var pair in safeNames  ) {

    if( !first ) sb.Append(", ");
    first = false;

    sb.Append("[");
    sb.Append( pair.ColumnName );
    sb.Append("]");
}

sb.Append( " ) VALUES ( " );

first = false;
foreach( var pair in safeNames ) {

    if( !first ) sb.Append(", ");
    first = false;

    sb.Append("@");
    sb.Append( pair.ColumnName );
}

sb.Append( ");" );

using( SqlCommand cmd = connection.CreateCommand() ) {

    cmd.CommandText = sb.ToString();

    foreach( var pair in safeNames ) {
        cmd.Parameters.Add( '@' + pair.ColumnName ).Value = pair.Value;
    }

    cmd.ExecuteNonQuery();
}

2。使用实体框架

如果您正在使用实体框架,则可以使用分离的实体来执行INSERT,但请注意,您不能轻松地选择性地排除列 - 默认情况下,实体框架将始终包含所有INSERT中的实体成员,因此如果您的列具有非NULL默认值,否则在新的分离的Entity对象中未定义,那么它们将以NULL值保存,因此覆盖非NULL默认值,因此会被警告

MyEntity detached = new MyEntity();

Type entityType = typeof(MyEntity);

IEnumerable<PropertyInfo> properties = entityType 
    .GetProperties()
    // Exclude inherited and special properties:
    .Where( pi => pi.DeclaringType == entityType && !pi.IsSpecialName )
    // Exclude non-read/write properties:
    .Where( pi => pi.CanRead && pi.CanWrite )
    // Exclude non-scalar properties:
    .Where( pi => pi.PropertyType.IsPrimitive || pi.PropertyType == typeof(String) );

foreach( PropertyInfo property in properties ) {

    Object value;
    if( dict.TryGetValue( property.Name, out value ) ) {

        property.SetValue( detached, value );
    }
}

MyDBContext dbContext = ...

// Attach the entity:
dbContext.TableName.Add( detached );

// Execute the INSERT:
dbContext.SaveChanges();

如果要从操作中排除某些列,则需要使用dbContext.Entry( $entity ).Property( e = e.PropertyName ).IsModified = false方法(虽然我不知道这是否适用于INSERT操作或仅UPDATE)。