| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- //
- // System.Data.Common.CommandBuilder.cs
- //
- // Author:
- // Tim Coleman ([email protected])
- //
- // Copyright (C) Tim Coleman, 2002
- //
- using System;
- using System.Collections;
- using System.ComponentModel;
- using System.Data;
- using System.Data.Common;
- using System.Text;
- namespace System.Data.SqlClient {
- public sealed class SqlCommandBuilder : Component
- {
- #region Fields
- DataTable dbSchemaTable;
- SqlDataAdapter adapter;
- string quotePrefix;
- string quoteSuffix;
- string[] columnNames;
- string tableName;
-
- SqlCommand deleteCommand;
- SqlCommand insertCommand;
- SqlCommand updateCommand;
- // Used to construct WHERE clauses
- static readonly string clause1 = "({0} IS NULL AND {1} IS NULL)";
- static readonly string clause2 = "({0} = {1})";
- #endregion // Fields
- #region Constructors
- public SqlCommandBuilder ()
- {
- dbSchemaTable = null;
- adapter = null;
- quoteSuffix = String.Empty;
- quotePrefix = String.Empty;
- }
- public SqlCommandBuilder (SqlDataAdapter adapter)
- : this ()
- {
- DataAdapter = adapter;
- }
- #endregion // Constructors
- #region Properties
- public SqlDataAdapter DataAdapter {
- get { return adapter; }
- set {
- adapter = value;
- if (adapter != null)
- adapter.RowUpdating += new SqlRowUpdatingEventHandler (RowUpdatingHandler);
- }
- }
- private string QuotedTableName {
- get { return GetQuotedString (tableName); }
- }
- public string QuotePrefix {
- get { return quotePrefix; }
- set {
- if (dbSchemaTable != null)
- throw new InvalidOperationException ("The QuotePrefix and QuoteSuffix properties cannot be changed once an Insert, Update, or Delete command has been generated.");
- quotePrefix = value;
- }
- }
- public string QuoteSuffix {
- get { return quoteSuffix; }
- set {
- if (dbSchemaTable != null)
- throw new InvalidOperationException ("The QuotePrefix and QuoteSuffix properties cannot be changed once an Insert, Update, or Delete command has been generated.");
- quoteSuffix = value;
- }
- }
- private SqlCommand SourceCommand {
- get {
- if (adapter != null)
- return adapter.SelectCommand;
- return null;
- }
- }
- #endregion // Properties
- #region Methods
- private void BuildCache (bool closeConnection)
- {
- SqlCommand sourceCommand = SourceCommand;
- if (sourceCommand == null)
- throw new InvalidOperationException ("The DataAdapter.SelectCommand property needs to be initialized.");
- SqlConnection connection = sourceCommand.Connection;
- if (connection == null)
- throw new InvalidOperationException ("The DataAdapter.SelectCommand.Connection property needs to be initialized.");
-
- if (dbSchemaTable == null) {
- if (connection.State == ConnectionState.Open)
- closeConnection = false;
- else
- connection.Open ();
-
- SqlDataReader reader = sourceCommand.ExecuteReader (CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo);
- dbSchemaTable = reader.GetSchemaTable ();
- if (closeConnection)
- connection.Close ();
- BuildInformation (dbSchemaTable);
- }
- }
-
- private void BuildInformation (DataTable schemaTable)
- {
- tableName = String.Empty;
- foreach (DataRow schemaRow in schemaTable.Rows) {
- if (tableName == String.Empty)
- tableName = (string) schemaRow ["BaseTableName"];
- if (tableName != (string) schemaRow["BaseTableName"])
- throw new InvalidOperationException ("Dynamic SQL generation is not supported against multiple base tables.");
- }
- dbSchemaTable = schemaTable;
- }
- private SqlCommand CreateDeleteCommand (DataRow row, DataTableMapping tableMapping)
- {
- // If no table was found, then we can't do an delete
- if (QuotedTableName == String.Empty)
- return null;
- CreateNewCommand (ref deleteCommand);
- string command = String.Format ("DELETE FROM {0} ", QuotedTableName);
- StringBuilder columns = new StringBuilder ();
- StringBuilder where = new StringBuilder ();
- int parmIndex = 1;
- foreach (DataRow schemaRow in dbSchemaTable.Rows) {
- if (!IncludedInWhereClause (schemaRow))
- continue;
- if (where.Length > 0)
- where.Append (" AND ");
- bool isKey = (bool) schemaRow ["IsKey"];
- SqlParameter parameter = null;
- if (!isKey) {
- parameter = deleteCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
- where.Append ("(");
- where.Append (String.Format (clause1, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
- where.Append (" OR ");
- }
-
- parameter = deleteCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
- if (row != null)
- parameter.Value = row [parameter.SourceColumn, DataRowVersion.Current];
- where.Append (String.Format (clause2, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
- if (!isKey)
- where.Append (")");
- }
- // We're all done, so bring it on home
- string sql = String.Format ("{0} WHERE ( {1} )", command, where.ToString ());
- deleteCommand.CommandText = sql;
- return deleteCommand;
- }
- private SqlCommand CreateInsertCommand (DataRow row, DataTableMapping tableMapping)
- {
- if (QuotedTableName == String.Empty)
- return null;
- CreateNewCommand (ref insertCommand);
- string command = String.Format ("INSERT INTO {0}", QuotedTableName);
- string sql;
- StringBuilder columns = new StringBuilder ();
- StringBuilder values = new StringBuilder ();
- int parmIndex = 1;
- foreach (DataRow schemaRow in dbSchemaTable.Rows) {
- if (!IncludedInInsert (schemaRow))
- continue;
- if (parmIndex > 1) {
- columns.Append (" , ");
- values.Append (" , ");
- }
- SqlParameter parameter = insertCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
- if (row != null)
- parameter.Value = row [parameter.SourceColumn, DataRowVersion.Proposed];
- columns.Append (GetQuotedString (parameter.SourceColumn));
- values.Append (parameter.ParameterName);
- }
- sql = String.Format ("{0}( {1} ) VALUES ( {2} )", command, columns.ToString (), values.ToString ());
- insertCommand.CommandText = sql;
- return insertCommand;
- }
- private void CreateNewCommand (ref SqlCommand command)
- {
- SqlCommand sourceCommand = SourceCommand;
- if (command == null) {
- command = sourceCommand.Connection.CreateCommand ();
- command.CommandTimeout = sourceCommand.CommandTimeout;
- command.Transaction = sourceCommand.Transaction;
- }
- command.CommandType = CommandType.Text;
- command.UpdatedRowSource = UpdateRowSource.None;
- }
- private SqlCommand CreateUpdateCommand (DataRow row, DataTableMapping tableMapping)
- {
- // If no table was found, then we can't do an update
- if (QuotedTableName == String.Empty)
- return null;
- CreateNewCommand (ref updateCommand);
- string command = String.Format ("UPDATE {0} SET ", QuotedTableName);
- StringBuilder columns = new StringBuilder ();
- StringBuilder where = new StringBuilder ();
- int parmIndex = 1;
- // First, create the X=Y list for UPDATE
- foreach (DataRow schemaRow in dbSchemaTable.Rows) {
- if (columns.Length > 0)
- columns.Append (" , ");
- SqlParameter parameter = updateCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
- if (row != null)
- parameter.Value = row [parameter.SourceColumn, DataRowVersion.Proposed];
- columns.Append (String.Format ("{0} = {1}", GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
- }
- // Now, create the WHERE clause. This may be optimizable, but it would be ugly to incorporate
- // into the loop above. "Premature optimization is the root of all evil." -- Knuth
- foreach (DataRow schemaRow in dbSchemaTable.Rows) {
- if (!IncludedInWhereClause (schemaRow))
- continue;
- if (where.Length > 0)
- where.Append (" AND ");
- bool isKey = (bool) schemaRow ["IsKey"];
- SqlParameter parameter = null;
- if (!isKey) {
- parameter = updateCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
- where.Append ("(");
- where.Append (String.Format (clause1, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
- where.Append (" OR ");
- }
-
- parameter = updateCommand.Parameters.Add (CreateParameter (parmIndex++, schemaRow));
- if (row != null)
- parameter.Value = row [parameter.SourceColumn, DataRowVersion.Current];
- where.Append (String.Format (clause2, GetQuotedString (parameter.SourceColumn), parameter.ParameterName));
- if (!isKey)
- where.Append (")");
- }
- // We're all done, so bring it on home
- string sql = String.Format ("{0}{1} WHERE ( {2} )", command, columns.ToString (), where.ToString ());
- updateCommand.CommandText = sql;
- return updateCommand;
- }
- private SqlParameter CreateParameter (int parmIndex, DataRow schemaRow)
- {
- string name = String.Format ("@p{0}", parmIndex);
- string sourceColumn = (string) schemaRow ["BaseColumnName"];
- SqlDbType sqlDbType = (SqlDbType) schemaRow ["ProviderType"];
- int size = (int) schemaRow ["ColumnSize"];
- return new SqlParameter (name, sqlDbType, size, sourceColumn);
- }
- public static void DeriveParameters (SqlCommand command)
- {
- command.DeriveParameters ();
- }
- [MonoTODO]
- protected override void Dispose (bool disposing)
- {
- }
- public SqlCommand GetDeleteCommand ()
- {
- BuildCache (true);
- return CreateDeleteCommand (null, null);
- }
- public SqlCommand GetInsertCommand ()
- {
- BuildCache (true);
- return CreateInsertCommand (null, null);
- }
- private string GetQuotedString (string value)
- {
- if (value == String.Empty || value == null)
- return value;
- if (quotePrefix == String.Empty && quoteSuffix == String.Empty)
- return value;
- return String.Format ("{0}{1}{2}", quotePrefix, value, quoteSuffix);
- }
- public SqlCommand GetUpdateCommand ()
- {
- BuildCache (true);
- return CreateUpdateCommand (null, null);
- }
- private bool IncludedInInsert (DataRow schemaRow)
- {
- // If the parameter has one of these properties, then we don't include it in the insert:
- // AutoIncrement, Hidden, Expression, RowVersion, ReadOnly
- if ((bool) schemaRow ["IsAutoIncrement"])
- return false;
- if ((bool) schemaRow ["IsHidden"])
- return false;
- if ((bool) schemaRow ["IsExpression"])
- return false;
- if ((bool) schemaRow ["IsRowVersion"])
- return false;
- if ((bool) schemaRow ["IsReadOnly"])
- return false;
- return true;
- }
- private bool IncludedInUpdate (DataRow schemaRow)
- {
- // If the parameter has one of these properties, then we don't include it in the insert:
- // AutoIncrement, Hidden, RowVersion
- if ((bool) schemaRow ["IsAutoIncrement"])
- return false;
- if ((bool) schemaRow ["IsHidden"])
- return false;
- if ((bool) schemaRow ["IsRowVersion"])
- return false;
- return true;
- }
- private bool IncludedInWhereClause (DataRow schemaRow)
- {
- if ((bool) schemaRow ["IsLong"])
- return false;
- return true;
- }
- [MonoTODO]
- public void RefreshSchema ()
- {
- tableName = String.Empty;
- dbSchemaTable = null;
- }
- #endregion // Methods
- #region Event Handlers
- private void RowUpdatingHandler (object sender, SqlRowUpdatingEventArgs e)
- {
- if (e.Status != UpdateStatus.Continue)
- return;
- switch (e.StatementType) {
- case StatementType.Delete:
- deleteCommand = e.Command;
- break;
- case StatementType.Insert:
- insertCommand = e.Command;
- break;
- case StatementType.Update:
- updateCommand = e.Command;
- break;
- default:
- return;
- }
- BuildCache (false);
- switch (e.StatementType) {
- case StatementType.Delete:
- e.Command = CreateDeleteCommand (e.Row, e.TableMapping);
- e.Status = UpdateStatus.Continue;
- break;
- case StatementType.Insert:
- e.Command = CreateInsertCommand (e.Row, e.TableMapping);
- e.Status = UpdateStatus.Continue;
- break;
- case StatementType.Update:
- e.Command = CreateUpdateCommand (e.Row, e.TableMapping);
- e.Status = UpdateStatus.Continue;
- break;
- }
-
- if (e.Command != null && e.Row != null) {
- e.Row.AcceptChanges ();
- e.Status = UpdateStatus.SkipCurrentRow;
- }
- }
- #endregion // Event Handlers
- }
- }
|