我一直在尝试一种方法,该方法采用一个列名和一个值,我希望在基本测试数据库上更新该值,而使用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;";
现在可以产生正确的结果
答案 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} =
WHERE TID = waitsForConnectivity
AND id = {{2}};";
db.Database.ExecuteSqlCommand(s_q_el, nval, paid, id);
在后一个示例中,SQL仍使用参数发送到后端,Linq自动将它们创建为名为@ p0,@ p1 ...的参数,并进行相应的绑定。这可能会遇到一些问题,例如没有选择正确的预期数据类型,但在大多数情况下都会起作用。
使用ExecuteSqlCommand有时会非常方便,并且比获取实体,更新和保存回来更为方便(即:批量更新或删除-如果您的条件可能返回多个行以进行更新,则为IOW)。