C#EF使用ExecuteSqlCommand的正确方法

C#EF使用ExecuteSqlCommand的正确方法,c#,sql,entity-framework,C#,Sql,Entity Framework,我一直在尝试一种方法,该方法接受一个列名称和一个我希望在基本测试数据库上更新的值,但我似乎无法使用SqlParameters获得结果?当我硬编码查询时,我看到db表被更新了吗 请务必理解我在以下查询中的错误: public bool UpdateTestDataTable(string TID, string ColumnName, string ColumnValue) { try { if (!string.IsNullOrEmpty(TID))

我一直在尝试一种方法,该方法接受一个列名称和一个我希望在基本测试数据库上更新的值,但我似乎无法使用SqlParameters获得结果?当我硬编码查询时,我看到db表被更新了吗

请务必理解我在以下查询中的错误:

public bool UpdateTestDataTable(string TID, string ColumnName, string ColumnValue)
{
    try
    {
        if (!string.IsNullOrEmpty(TID))
        {
            using (var db = new TestDBContext())
            {
                var rId = db.TempDb.SingleOrDefault(p => p.TID == TID);

                string s_q_el = @"UPDATE dbo.TempDb
                               SET @Column = @NewValue
                               WHERE TID = @TID
                               AND id = @DbId;";


                //This Works
                //string sql2 = @"UPDATE dbo.TempDb
                //               SET TestData1 = 'TestingABC'
                //               WHERE TID = '66A46552E9A0B912457CE804A54CE1AF'
                //               AND id = @DbId;";

                var col = new SqlParameter("@Column", SqlDbType.NVarChar)
                {
                    Value = ColumnName
                };

                var nval = new SqlParameter("@NewValue", SqlDbType.NVarChar)
                {
                    Value = ColumnValue
                };
                var paid = new SqlParameter("@PAID", SqlDbType.NVarChar)
                {
                    Value = TID
                };
                var id = new SqlParameter("@DbId", SqlDbType.Int)
                {
                    Value = rId.Id
                };


                db.Database.ExecuteSqlCommand(s_q_el, parameters: new[] { col, nval, paid, id});

                //db.Database.ExecuteSqlCommand(sql2);
                db.SaveChanges();

                return true;
            }
        }
        else
        {
            return false;
        }
    }
    catch(Exception UADT_EX)
    {
        Console.WriteLine($"Error: {UADT_EX.message}");
        return false;
    }
}
电话:

UpdateTestDataTable("66A46552E9A0B912457CE804A54CE1AF", "TestData1","BLAHBLAH123");
我已经测试了很多方法,但我觉得我完全忽略了这里显而易见的东西? 之所以采用这种方法,是因为我希望使用单个函数在整个测试应用程序中更新各种列数据

非常感谢

编辑

我根据收到的评论更新了查询,但以下做法是否不好

string s_q_el = $"UPDATE dbo.TempDb SET {ColumnName}= @NewValue WHERE TID = @TID AND id = @DbId;";

由于这会产生正确的结果

,因为您有一个实体模型,为什么不使用反射呢。与DbContext上的帮助器方法类似:

public void UpdateEntity<T>(int id, string propertyName, string propertyValue) where T:class
{
    var entity = this.Set<T>().Find(id);
    var prop = typeof(T).GetProperty(propertyName);
    var val = Convert.ChangeType(propertyValue, prop.PropertyType);
    prop.SetValue(entity, val);
    this.SaveChanges();
}
public void UpdateEntity(int-id,string-propertyName,string-propertyValue),其中T:class
{
var entity=this.Set().Find(id);
var prop=typeof(T).GetProperty(propertyName);
var val=Convert.ChangeType(propertyValue,prop.PropertyType);
属性设置值(实体,val);
这是SaveChanges();
}
如果您知道密钥属性名称,甚至可以在不首先从数据库获取实体的情况下执行此操作。乙二醇

public void UpdateEntity<T>(int id, string keyPropertyName, string propertyName, string propertyValue) where T:class, new()
{

    var entity = new T();
    typeof(T).GetProperty(keyPropertyName).SetValue(entity,Id);
    this.Set<T>().Add(entity);

    var prop = typeof(T).GetProperty(propertyName);
    var val = Convert.ChangeType(propertyValue, prop.PropertyType);
    prop.SetValue(entity, val);


    this.Entry(entity).State = EntityState.Unchanged;
    foreach (var p in this.Entry(entity).Properties)
    {
        p.IsModified = p.Metadata.Name == propertyName;
    }
    this.SaveChanges();
}
public void UpdateEntity(int-id,string-keyPropertyName,string-propertyName,string-propertyValue),其中T:class,new()
{
var entity=newt();
typeof(T).GetProperty(keyPropertyName).SetValue(实体,Id);
this.Set().Add(实体);
var prop=typeof(T).GetProperty(propertyName);
var val=Convert.ChangeType(propertyValue,prop.PropertyType);
属性设置值(实体,val);
this.Entry(entity).State=EntityState.Unchanged;
foreach(此.Entry(entity.Properties)中的var p)
{
p、 IsModified=p.Metadata.Name==propertyName;
}
这是SaveChanges();
}

既然您有一个实体模型,为什么不直接使用反射呢。与DbContext上的帮助器方法类似:

public void UpdateEntity<T>(int id, string propertyName, string propertyValue) where T:class
{
    var entity = this.Set<T>().Find(id);
    var prop = typeof(T).GetProperty(propertyName);
    var val = Convert.ChangeType(propertyValue, prop.PropertyType);
    prop.SetValue(entity, val);
    this.SaveChanges();
}
public void UpdateEntity(int-id,string-propertyName,string-propertyValue),其中T:class
{
var entity=this.Set().Find(id);
var prop=typeof(T).GetProperty(propertyName);
var val=Convert.ChangeType(propertyValue,prop.PropertyType);
属性设置值(实体,val);
这是SaveChanges();
}
如果您知道密钥属性名称,甚至可以在不首先从数据库获取实体的情况下执行此操作。乙二醇

public void UpdateEntity<T>(int id, string keyPropertyName, string propertyName, string propertyValue) where T:class, new()
{

    var entity = new T();
    typeof(T).GetProperty(keyPropertyName).SetValue(entity,Id);
    this.Set<T>().Add(entity);

    var prop = typeof(T).GetProperty(propertyName);
    var val = Convert.ChangeType(propertyValue, prop.PropertyType);
    prop.SetValue(entity, val);


    this.Entry(entity).State = EntityState.Unchanged;
    foreach (var p in this.Entry(entity).Properties)
    {
        p.IsModified = p.Metadata.Name == propertyName;
    }
    this.SaveChanges();
}
public void UpdateEntity(int-id,string-keyPropertyName,string-propertyName,string-propertyValue),其中T:class,new()
{
var entity=newt();
typeof(T).GetProperty(keyPropertyName).SetValue(实体,Id);
this.Set().Add(实体);
var prop=typeof(T).GetProperty(propertyName);
var val=Convert.ChangeType(propertyValue,prop.PropertyType);
属性设置值(实体,val);
this.Entry(entity).State=EntityState.Unchanged;
foreach(此.Entry(entity.Properties)中的var p)
{
p、 IsModified=p.Metadata.Name==propertyName;
}
这是SaveChanges();
}

如注释中所述,您不能参数化列名,但可以构建一个存储过程,该存储过程可以使用参数并从中生成SQL:

CREATE PROCEDURE updateFromParameters 
  @column varchar(max),
  @newValue varchar(max),
  @TID varchar(max),
  @id int
AS

DECLARE @s_q_el varchar(max) 

SET @s_q_el = 'UPDATE dbo.TempDB ' 
    + 'SET ' + @column + ' = ''' + @newValue + ''''
    + 'WHERE TID = ''' + @TID + ''''
    + 'id = ' + @id

EXEC @s_q_el
然后只需从C代码执行存储过程:


如注释中所述,您不能参数化列名,但可以构建一个存储过程,该存储过程可以使用参数并从中生成SQL:

CREATE PROCEDURE updateFromParameters 
  @column varchar(max),
  @newValue varchar(max),
  @TID varchar(max),
  @id int
AS

DECLARE @s_q_el varchar(max) 

SET @s_q_el = 'UPDATE dbo.TempDB ' 
    + 'SET ' + @column + ' = ''' + @newValue + ''''
    + 'WHERE TID = ''' + @TID + ''''
    + 'id = ' + @id

EXEC @s_q_el
然后只需从C代码执行存储过程:


如图所示,您可以进行轻微修改:

string s_q_el = $@"UPDATE dbo.TempDb
                  SET {ColumnName} = @NewValue
                  WHERE TID = @TID
                  AND id = @DbId;";

var nval = new SqlParameter("@NewValue", SqlDbType.NVarChar)
{
   Value = ColumnValue
};
var paid = new SqlParameter("@PAID", SqlDbType.NVarChar)
{
   Value = TID
};
var id = new SqlParameter("@DbId", SqlDbType.Int)
{
   Value = rId.Id
};

db.Database.ExecuteSqlCommand(s_q_el, nval, paid, id);
或者您也可以这样做:

string s_q_el = $@"UPDATE dbo.TempDb
                  SET {ColumnName} = {{0}}
                  WHERE TID = {{1}}
                  AND id = {{2}};";

db.Database.ExecuteSqlCommand(s_q_el, nval, paid, id);
在后一个示例中,SQL仍然使用参数发送到后端,Linq会自动将它们创建为名为@p0、@p1。。。并具有相应的约束力。这可能会有一些问题,比如没有选择正确的数据类型,但在大多数情况下都会起作用


使用ExecuteSqlCommand有时非常方便,并且比获取实体、更新和保存更可取(即:批量更新或删除-如果您的条件可能返回多行进行更新)。

您可以如所示执行此操作,稍加修改:

string s_q_el = $@"UPDATE dbo.TempDb
                  SET {ColumnName} = @NewValue
                  WHERE TID = @TID
                  AND id = @DbId;";

var nval = new SqlParameter("@NewValue", SqlDbType.NVarChar)
{
   Value = ColumnValue
};
var paid = new SqlParameter("@PAID", SqlDbType.NVarChar)
{
   Value = TID
};
var id = new SqlParameter("@DbId", SqlDbType.Int)
{
   Value = rId.Id
};

db.Database.ExecuteSqlCommand(s_q_el, nval, paid, id);
或者您也可以这样做:

string s_q_el = $@"UPDATE dbo.TempDb
                  SET {ColumnName} = {{0}}
                  WHERE TID = {{1}}
                  AND id = {{2}};";

db.Database.ExecuteSqlCommand(s_q_el, nval, paid, id);
在后一个示例中,SQL仍然使用参数发送到后端,Linq会自动将它们创建为名为@p0、@p1。。。并具有相应的约束力。这可能会有一些问题,比如没有选择正确的数据类型,但在大多数情况下都会起作用


使用ExecuteSqlCommand有时非常方便,并且比获取实体、更新和保存(即:批量更新或删除-如果您的条件可能会返回多行进行更新)更可取。

您不能参数化列名(或表名)。参数仅用于传递值。值是一种基本数据类型,如字符串、数字、guid、日期时间等。啊,他妈的,照你猜的做,我没想到会尝试另一种方法,然后你不能参数化列名(或表名)。参数仅用于传递值。值是一种原始数据类型,如字符串、数字、guid、日期时间等。啊,该死的,就像你猜的那样,我没想到会尝试另一种方法,然后啊,实际上看起来更好更干净,我现在要测试一下,因为我在过去一周才开始学习EF。非常感谢这一点,我也在msdn上找到了关于Set的参考资料,因为我想完全理解这一点,可以说它工作得非常好,正在做我需要的事情。我真的很欣赏它。事实上,它看起来更好、更干净,我现在将测试这一点,因为我在过去一周才开始学习EF。非常感谢这一点,我也在msdn上找到了关于Set的参考资料,因为我想完全理解这一点,可以说这非常有效,并且正在做我需要的事情。非常感谢