3 namespace System.Data
\r
6 /// Summary description for MergeManager.
\r
8 internal class MergeManager
\r
10 internal static void Merge(DataSet targetSet, DataSet sourceSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
\r
12 if(targetSet == null)
\r
13 throw new ArgumentNullException("targetSet");
\r
14 if(sourceSet == null)
\r
15 throw new ArgumentNullException("sourceSet");
\r
17 foreach (DataTable t in sourceSet.Tables)
\r
18 MergeManager.Merge(targetSet, t, preserveChanges, missingSchemaAction);
\r
22 internal static void Merge(DataSet targetSet, DataTable sourceTable, bool preserveChanges, MissingSchemaAction missingSchemaAction)
\r
24 if(targetSet == null)
\r
25 throw new ArgumentNullException("targetSet");
\r
26 if(sourceTable == null)
\r
27 throw new ArgumentNullException("sourceTable");
\r
30 if (!AdjustSchema(targetSet, sourceTable, missingSchemaAction))
\r
32 DataTable targetTable = targetSet.Tables[sourceTable.TableName];
\r
33 if (targetTable != null)
\r
35 checkColumnTypes(targetTable, sourceTable); // check that the colums datatype is the same
\r
36 fillData(targetTable, sourceTable, preserveChanges);
\r
41 internal static void Merge(DataSet targetSet, DataRow[] sourceRows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
\r
43 if(targetSet == null)
\r
44 throw new ArgumentNullException("targetSet");
\r
45 if(sourceRows == null)
\r
46 throw new ArgumentNullException("sourceRows");
\r
48 for (int i = 0; i < sourceRows.Length; i++)
\r
50 DataRow row = sourceRows[i];
\r
51 DataTable sourceTable = row.Table;
\r
52 if (!AdjustSchema(targetSet, sourceTable, missingSchemaAction))
\r
54 DataTable targetTable = targetSet.Tables[row.Table.TableName];
\r
55 if (targetTable != null)
\r
57 checkColumnTypes(targetTable, row.Table);
\r
58 MergeRow(targetTable, row, preserveChanges);
\r
63 // merge a row into a target table.
\r
64 private static void MergeRow(DataTable targetTable, DataRow row, bool preserveChanges)
\r
66 DataColumnCollection columns = row.Table.Columns;
\r
67 DataColumn[] primaryKeys = targetTable.PrimaryKey;
\r
68 DataRow targetRow = null;
\r
69 DataRowVersion version = DataRowVersion.Default;
\r
70 if (row.RowState == DataRowState.Deleted)
\r
71 version = DataRowVersion.Original;
\r
73 if (primaryKeys != null && primaryKeys.Length > 0) // if there are any primary key.
\r
75 // initiate an array that has the values of the primary keys.
\r
76 object[] keyValues = new object[primaryKeys.Length];
\r
78 for (int j = 0; j < keyValues.Length; j++)
\r
80 keyValues[j] = row[primaryKeys[j].ColumnName, version];
\r
83 // find the row in the target table.
\r
84 targetRow = targetTable.Rows.Find(keyValues);
\r
86 // row doesn't exist in target table, or there are no primary keys.
\r
87 // create new row and copy values from source row to the new row.
\r
88 if (targetRow == null)
\r
90 targetRow = targetTable.NewRow();
\r
91 row.CopyValuesToRow(targetRow);
\r
92 targetTable.Rows.Add(targetRow);
\r
94 // row exists in target table, and presere changes is false -
\r
95 // change the values of the target row to the values of the source row.
\r
96 else if (!preserveChanges)
\r
98 row.CopyValuesToRow(targetRow);
\r
105 // adjust the table schema according to the missingschemaaction param.
\r
106 // return false if adjusting fails.
\r
107 private static bool AdjustSchema(DataSet targetSet, DataTable sourceTable, MissingSchemaAction missingSchemaAction)
\r
109 string tableName = sourceTable.TableName;
\r
111 // if the source table not exists in the target dataset
\r
112 // we act according to the missingschemaaction param.
\r
113 int tmp = targetSet.Tables.IndexOf(tableName);
\r
114 // we need to check if it is equals names
\r
115 if (tmp != -1 && !targetSet.Tables[tmp].TableName.Equals(tableName))
\r
119 if (missingSchemaAction == MissingSchemaAction.Ignore)
\r
121 if (missingSchemaAction == MissingSchemaAction.Error)
\r
122 throw new ArgumentException("Target DataSet missing definition for "+ tableName + ".");
\r
123 targetSet.Tables.Add((DataTable)sourceTable.Clone());
\r
126 DataTable table = targetSet.Tables[tableName];
\r
128 if (!CheckPrimaryKeys(table, sourceTable))
\r
131 for (int i = 0; i < sourceTable.Columns.Count; i++)
\r
133 DataColumn col = sourceTable.Columns[i];
\r
134 // if a column from the source table doesn't exists in the target table
\r
135 // we act according to the missingschemaaction param.
\r
136 if(!table.Columns.Contains(col.ColumnName))
\r
138 if (missingSchemaAction == MissingSchemaAction.Ignore)
\r
140 if (missingSchemaAction == MissingSchemaAction.Error)
\r
141 throw new ArgumentException(("Column '" + col.ColumnName + "' does not belong to table Items."));
\r
143 table.Columns.Add(new DataColumn(col.ColumnName, col.DataType, col.Expression, col.ColumnMapping));
\r
150 // find if there is a valid matching between the targetTable PrimaryKey and the
\r
151 // sourceTable primatyKey.
\r
152 // return true if there is a match, else return false and raise a MergeFailedEvent.
\r
153 private static bool CheckPrimaryKeys(DataTable targetTable, DataTable sourceTable)
\r
155 // if the length of one of the tables primarykey if 0 - there is nothing to check.
\r
156 if (targetTable.PrimaryKey.Length != 0 && sourceTable.PrimaryKey.Length != 0)
\r
158 // if the length of primarykey is not equal - merge fails
\r
159 if (targetTable.PrimaryKey.Length != sourceTable.PrimaryKey.Length)
\r
161 string message = "<target>.PrimaryKey and <source>.PrimaryKey have different Length.";
\r
162 MergeFailedEventArgs e = new MergeFailedEventArgs(sourceTable, message);
\r
163 targetTable.DataSet.OnMergeFailed(e);
\r
168 // we have to see that each primary column in the target table
\r
169 // has a column with the same name in the sourcetable primarykey columns.
\r
171 DataColumn[] targetDataColumns = targetTable.PrimaryKey;
\r
172 DataColumn[] srcDataColumns = sourceTable.PrimaryKey;
\r
174 // loop on all primary key columns in the targetTable.
\r
175 for (int i = 0; i < targetDataColumns.Length; i++)
\r
177 foundMatch = false;
\r
178 DataColumn col = targetDataColumns[i];
\r
180 // find if there is a column with the same name in the
\r
181 // sourceTable primary key columns.
\r
182 for (int j = 0; j < srcDataColumns.Length; j++)
\r
184 if (srcDataColumns[j].ColumnName == col.ColumnName)
\r
192 string message = "Mismatch columns in the PrimaryKey : <target>." + col.ColumnName + " versus <source>." + srcDataColumns[i].ColumnName + ".";
\r
193 MergeFailedEventArgs e = new MergeFailedEventArgs(sourceTable, message);
\r
194 targetTable.DataSet.OnMergeFailed(e);
\r
205 // fill the data from the source table to the target table
\r
206 private static void fillData(DataTable targetTable, DataTable sourceTable, bool preserveChanges)
\r
208 for (int i = 0; i < sourceTable.Rows.Count; i++)
\r
210 DataRow row = sourceTable.Rows[i];
\r
211 MergeRow(targetTable, row, preserveChanges);
\r
215 // check tha column from 2 tables that has the same name also has the same datatype.
\r
216 private static void checkColumnTypes(DataTable targetTable, DataTable sourceTable)
\r
218 for (int i = 0; i < sourceTable.Columns.Count; i++)
\r
220 DataColumn fromCol = sourceTable.Columns[i];
\r
221 DataColumn toCol = targetTable.Columns[fromCol.ColumnName];
\r
222 if((toCol != null) && (toCol.DataType != fromCol.DataType))
\r
223 throw new DataException("<target>." + fromCol.ColumnName + " and <source>." + fromCol.ColumnName + " have conflicting properties: DataType property mismatch.");
\r