C#EF使用ExecuteSqlCommand的正确方法

时间:2018-10-17 15:51:53

标签: c# sql entity-framework

我一直在尝试一种方法,该方法采用一个列名和一个值,我希望在基本测试数据库上更新该值,而使用SqlParameters似乎无法获取和得到结果?当我对查询进行硬编码时,我看到数据库表已更新吗?

很高兴了解以下查询在做什么:

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;";

现在可以产生正确的结果

3 个答案:

答案 0 :(得分:2)

由于您拥有实体模型,所以为什么不直接使用反射。像您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();
}

如果您知道键属性名称,那么甚至无需先从数据库中获取实体就可以执行此操作。 EG

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();
}

答案 1 :(得分:0)

如注释中所述,您无法参数化列名,但是可以构建一个可以使用参数并从中构建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#代码中执行存储过程即可:

using (var command = new SqlCommand("updateFromParameters", conn) ) {

   command.CommandType = CommandType.StoredProcedure;

   // add your parameters here

   conn.Open();
   command.ExecuteNonQuery();
}

答案 2 :(得分:0)

您可以按照显示的进行操作,并稍加修改:

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} = enter image description here
                  WHERE TID = waitsForConnectivity
                  AND id = {{2}};";

db.Database.ExecuteSqlCommand(s_q_el, nval, paid, id);

在后一个示例中,SQL仍使用参数发送到后端,Linq自动将它们创建为名为@ p0,@ p1 ...的参数,并进行相应的绑定。这可能会遇到一些问题,例如没有选择正确的预期数据类型,但在大多数情况下都会起作用。

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