ORM和部分存储过程更新

时间:2014-04-08 16:11:09

标签: c# sql stored-procedures orm

想象一下使用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操作映射到存储过程时,是否存在仅用于管理部分更新的良好模式?

1 个答案:

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