C # EF Правильный способ использования ExecuteSqlCommand - PullRequest
0 голосов
/ 17 октября 2018

Я пробовал метод, который принимает имя столбца и значение, которое я хочу обновить в базовом тестовом БД, и я не могу получить и результаты, используя 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");

Я тестировал довольно много способов, но подумал, что я здесь упускаю очевидное?Причина такого подхода в том, что я хотел бы, чтобы одна функция обновляла различные данные столбцов в тестовом приложении.

Большое спасибо

РЕДАКТИРОВАТЬ

Iобновил запрос, основываясь на полученных комментариях, но будет ли это плохой практикой?

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

Поскольку теперь это дает правильный результат

Ответы [ 3 ]

0 голосов
/ 17 октября 2018

Как указано в комментариях, вы не можете параметризовать имена столбцов, но вы можете создать хранимую процедуру, которая может использовать параметры и строить из них 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();
}
0 голосов
/ 17 октября 2018

Вы можете сделать это, как вы показали, немного изменив:

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 иногда очень удобно и предпочтительнее, чем получение объекта, обновление и сохранение обратно (т.е. массовое обновление илиdelete - IOW, если ваши критерии могут возвращать несколько строк для обновления).

0 голосов
/ 17 октября 2018

Так как у вас есть Entity Model, почему бы просто не использовать Reflection.Как этот вспомогательный метод в вашем 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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...