想象一下使用ORM映射的以下对象:
public class Employee
{
public int Id;
public string FirstName;
public string LastName;
}
如果我只更新FirstName属性,我的ORM通常会跟踪属性更改,并生成一个只更新该列的UPDATE语句,并带有Id谓词。
UPDATE Employees SET Firstname = 'Bob' WHERE ID = 1;
如果我现在更改我的ORM以使用存储过程进行更新,它会将所有对象属性作为参数发送到存储过程。
EXEC sp_updateEmployee @ID = 1, @Firstname = 'Bob', @Lastname = 'Smith'
对于较大的对象,写回所有字段可能会导致更大的UPDATES,因为可能会写入更多的索引。
当UPDATE操作映射到存储过程时,是否存在仅用于管理部分更新的良好模式?
答案 0 :(得分:0)
这会让新学校的开发人员烦恼,但是使用DataSets(无类型或无类型)可以通过帮助程序类轻松实现这一点。
public static void DynamicUpdateTable(string dbTableName, string primaryKey, DataTable table, bool deleteByFlag, params string[] ignoreColumns)
{
if (ignoreColumns == null)
ignoreColumns = new string[0];
if (table.Rows.Count == 0)
return;
using (SqlConnection conn = new SqlConnection(myConnectionString))
using (SqlCommand da = new SqlCommand())
{
da.Connection = conn;
da.Connection.Open();
// DELETES
string deleteSQL;
if (deleteByFlag)
deleteSQL = "UPDATE [" + dbTableName + "] SET Deleted = 1 WHERE [" + primaryKey + "] = @PrimaryKey";
else
deleteSQL = "DELETE FROM [" + dbTableName + "] WHERE [" + primaryKey + "] = @PrimaryKey";
da.CommandText = deleteSQL;
foreach (DataRow row in table.Select(null, null, DataViewRowState.Deleted))
{
da.Parameters.Clear();
da.Parameters.AddWithValue("@PrimaryKey", row[primaryKey, DataRowVersion.Original]);
da.ExecuteNonQuery();
}
// INSERTS
List<string> insertColumnNames = new List<string>();
foreach (DataColumn column in table.Columns)
{
if (!ignoreColumns.Contains(column.ColumnName) &&
!column.AutoIncrement &&
column.GetType() != typeof(byte[]))
insertColumnNames.Add(column.ColumnName);
}
string insertSQL =
"INSERT INTO [" + dbTableName + "] ([" + string.Join("], [", insertColumnNames.ToArray()) + "]) " +
"VALUES (@" + string.Join(", @", insertColumnNames.ToArray()) + ")";
da.CommandText = insertSQL;
foreach (DataRow row in table.Select(null, null, DataViewRowState.Added))
{
da.Parameters.Clear();
foreach (DataColumn column in table.Columns)
{
if (!ignoreColumns.Contains(column.ColumnName) &&
// ignore auto increment primary key
!column.AutoIncrement &&
// ignore all timestamps
column.GetType() != typeof(byte[]))
da.Parameters.AddWithValue("@" + column.ColumnName, row[column]);
}
da.ExecuteNonQuery();
}
// DYNAMIC UPDATE
foreach (DataRow row in table.Select(null, null, DataViewRowState.ModifiedCurrent))
{
da.Parameters.Clear();
// work out which columns have changed in the row
List<string> changedColumns = new List<string>();
foreach (DataColumn column in table.Columns)
{
if (!ignoreColumns.Contains(column.ColumnName) &&
!row[column, DataRowVersion.Original].Equals(row[column, DataRowVersion.Current]))
{
changedColumns.Add("[" + column.ColumnName + "] = @" + column.ColumnName);
da.Parameters.AddWithValue("@" + column.ColumnName, row[column, DataRowVersion.Current]);
}
}
// only update if there are actual changes
if (changedColumns.Count > 0)
{
string updateSQL =
"UPDATE [" + dbTableName + "] SET " + string.Join(", ", changedColumns.ToArray()) +
" WHERE [" + primaryKey + "] = @" + primaryKey;
da.Parameters.AddWithValue("@" + primaryKey, row[primaryKey]);
da.CommandText = updateSQL;
da.ExecuteNonQuery();
}
}
}
table.AcceptChanges();
}