Datei: NDOEnhancer/NDOEnhancer/Enhancer/Generator/NdoTransDiffGenerator.cs

Last Commit (e9b343b)
1 //
2 // Copyright (c) 2002-2022 Mirko Matytschak
3 // (www.netdataobjects.de)
4 //
5 // Author: Mirko Matytschak
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8 // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10 // Software, and to permit persons to whom the Software is furnished to do so, subject to the following
11 // conditions:
12
13 // The above copyright notice and this permission notice shall be included in all copies or substantial portions
14 // of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21
22
23 using System;
24 using System.IO;
25 using System.Data;
26 using System.Collections.Generic;
27 using System.Xml.Linq;
28 using NDO;
29 using NDO.Mapping;
30 using NDOInterfaces;
31 using System.Reflection;
 
 
32
33 namespace NDOEnhancer
34 {
35 ····/// <summary>
36 ····/// Zusammenfassung für SQLDiffGenerator.
37 ····/// </summary>
38 ····internal class NdoTransDiffGenerator
39 ····{
40 ········NDOMapping mappings;
41 ········MessageAdapter messages;
42 ········public void Generate(DataSet dsSchema, DataSet dsBak, string filename, NDOMapping mappings, MessageAdapter messages)
43 ········{
44 ············this.mappings = mappings;
45 ············this.messages = messages;
46
47 ············string diffFileName = filename.Replace(".ndo.sql", ".ndodiff." + mappings.SchemaVersion + ".xml");
48 ············bool isNewDiffFile = !File.Exists(diffFileName);
49 ············XElement rootElement = null;
50 ············string newSchema = null;
51 ············if (isNewDiffFile)
52 ············{
53 ················rootElement = new XElement( "NdoSchemaTransitions" );
54 ················rootElement.Add( new XComment( "NDO accumulates all schema changes in this diff file. Note: If you change the mapping schema version, a new diff file will be created. You can change the mapping schema version in the NDO configuration dialog. Don't use the Mapping Tool to change the schema information, because it will be overwritten by the value set in the configuration. For automatic builds set the schema version value in the .ndoproj file." ) );
55 ················newSchema = mappings.SchemaVersion + ".1";
56 ················rootElement.Add( new XAttribute( "schemaVersion", newSchema ) );
57 ············}
58 ············else
59 ············{
60 ················rootElement = XElement.Load( diffFileName );
61 ················string schemaVersion = rootElement.Attribute("schemaVersion").Value;
62 ················int p = schemaVersion.LastIndexOf( '.' );
63 ················int v = 1;
64 ················int.TryParse( schemaVersion.Substring( p + 1 ), out v );
65 ················if (p > -1)
66 ····················newSchema = mappings.SchemaVersion + "." + (v + 1);
67 ················else
68 ····················newSchema = mappings.SchemaVersion + ".1";
69
70 ················rootElement.Attribute( "schemaVersion" ).Value = newSchema;
71 ············}
72
73 XElement transElement = new XElement( "NdoSchemaTransition", new XAttribute( "schemaVersion", newSchema ) ) ;
74 ············rootElement.Add( transElement );
75
76 ············if (GenerateInternal( dsSchema, dsBak, transElement ))
77 ············{
 
 
78 ················rootElement.Save( diffFileName );
 
 
 
 
 
 
 
 
 
 
 
 
 
79 ············}
80 ········}
81
82 ········bool GenerateInternal(System.Data.DataSet dsNewSchema, System.Data.DataSet dsOldSchema, XElement transElement)
83 ········{
84 ············bool hasChanges = false;
85 ············foreach(DataTable dt in dsNewSchema.Tables)
86 ············{
87 ················if (!dsOldSchema.Tables.Contains(dt.TableName))
88 ················{
89 ····················transElement.Add( CreateTable( dt ) );
90 ····················hasChanges = true;
91 ················}
92 ················else
93 ················{
94 ····················DataTable dtOld = dsOldSchema.Tables[dt.TableName];
95 ····················List<DataColumn> addedColumns = new List<DataColumn>();
96 ····················List<DataColumn> removedColumns = new List<DataColumn>();
97 ····················List<DataColumn> changedColumns = new List<DataColumn>();
98 ····················foreach(DataColumn dc in dt.Columns)
99 ····················{
100 ························if (!dtOld.Columns.Contains(dc.ColumnName))
101 ························{
102 ····························addedColumns.Add(dc);
103 ························}
104 ························else
105 ························{
106 ····························DataColumn dcOld = dtOld.Columns[dc.ColumnName];
107 ····························if (dc.DataType != dcOld.DataType || dc.MaxLength != dcOld.MaxLength)
108 ································changedColumns.Add(dc);
109 ························}
110 ····················}
111 ····················foreach(DataColumn dc in dtOld.Columns)
112 ····················{
113 ························if (!dt.Columns.Contains(dc.ColumnName))
114 ························{
115 ····························removedColumns.Add(dc);
116 ························}
117 ····················}
118 ····················if (addedColumns.Count > 0 || removedColumns.Count > 0 || changedColumns.Count > 0)
119 ························hasChanges = true;
120
121 ····················if (!hasChanges)
122 ························continue;
123
124 ····················XElement changeTableElement = ChangeTable(dt, addedColumns, removedColumns, changedColumns);
125 ····················if (changeTableElement.HasElements)
126 ························transElement.Add( changeTableElement );
127
128 ················}
129 ············}
130
131 ············foreach (DataTable dt in dsOldSchema.Tables)
132 ············{
133 ················if (!dsNewSchema.Tables.Contains( dt.TableName ))
134 ················{
135 ····················XElement dropTableElement = new XElement( "DropTable", new XAttribute( "name", dt.TableName ) );
136 ····················transElement.Add( dropTableElement );
137 ····················hasChanges = true;
138 ················}
139 ············}
140
141 ············return hasChanges;
142 ········}
143
144 ········XElement ChangeTable(DataTable dt, List<DataColumn> addedColumns, List<DataColumn> removedColums, List<DataColumn> changedColumns)
145 ········{
146 ············XElement alterTableElement = new XElement( "AlterTable", new XAttribute( "name", dt.TableName ) );
147
148 ············foreach(DataColumn dc in addedColumns)
149 ············{
150 ················XElement addColumnElement = new XElement( "AddColumn", new XAttribute( "name", dc.ColumnName ) );
151 ················CreateColumn(addColumnElement, dc, GetClassForTable(dt.TableName, this.mappings), false);
152 ················alterTableElement.Add( addColumnElement );
153 ············}
154
155 ············foreach(DataColumn dc in removedColums)
156 ············{
157 ················XElement dropColumnElement = new XElement( "DropColumn", new XAttribute( "name", dc.ColumnName ) );
158 ················alterTableElement.Add( dropColumnElement );
159 ············}
160
161 ············foreach(DataColumn dc in changedColumns)
162 ············{
163 ················XElement alterColumnElement = new XElement( "AlterColumn", new XAttribute( "name", dc.ColumnName ) );
164 ················CreateColumn(alterColumnElement, dc, GetClassForTable(dt.TableName, this.mappings), false);
165 ················alterTableElement.Add( alterColumnElement );
166 ············}
167
168 ············if (removedColums.Count > 0)
169 ············{
170 ················alterTableElement.Add( new XComment( "If you need to rename a column use the following syntax:" ) );
171 ················alterTableElement.Add( new XComment( "<RenameColumn oldName=\"...\" newName=\"...\" />" ) );
172 ············}
173
174 ············return alterTableElement;············
175 ········}
176
177 ········protected XElement CreateTable(DataTable dt)
178 ········{
179 ············XElement createTableElement = new XElement( "CreateTable", new XAttribute( "name", dt.TableName ) );
180
181 ············Class cl = FindClass(dt.TableName, mappings);
182
183 ············DataColumn[] primaryKeyColumns = dt.PrimaryKey;
184 ············bool hasPrimaryKeyColumns = primaryKeyColumns.Length > 0;
185
186 ············for (int i = 0; i < dt.Columns.Count; i++)
187 ············{
188 ················System.Data.DataColumn dc = dt.Columns[i];
189
190 ················bool isPrimary = false;
191 ················foreach (DataColumn pkc in primaryKeyColumns)
192 ················{
193 ····················if (pkc.ColumnName == dc.ColumnName)
194 ····················{
195 ························isPrimary = true;
196 ························break;
197 ····················}
198 ················}
199
200 ················XElement createColumnElement = new XElement( "CreateColumn", new XAttribute( "name", dc.ColumnName ) );
201 ················CreateColumn(createColumnElement, dc, cl, isPrimary);
202 ················createTableElement.Add( createColumnElement );
203 ············}
204
205 ············return createTableElement;
206 ········}
207
208 ········protected NDO.Mapping.Class FindClass(string tableName, NDOMapping mappings)
209 ········{
210 ············Class result = null;
211 ············foreach(Class cl in mappings.Classes)
212 ············{
213 ················if (cl.TableName == tableName)
214 ················{
215 ····················result = cl;
216 ····················break;
217 ················}
218 ············}
219 ············return result;
220 ········}
221
222 ········protected void CreateColumn(XElement addColumnElement, DataColumn dc, Class cl, bool isPrimary)
223 ········{
224 ············Type t = dc.DataType;
225 ············addColumnElement.Add( new XAttribute( "type", t.FullName + "," + new AssemblyName( t.Assembly.FullName ).Name ) );
226
227 ············if (isPrimary)
228 ················addColumnElement.Add( new XAttribute( "isPrimary", "true" ) );
229
230 ············if (cl != null)
231 ············{
232 ················Field field = FindField(dc.ColumnName, cl);
233
234 ················if (null != field)
235 ················{
236 ····················if (0 != field.Column.Size && !field.Column.IgnoreColumnSizeInDDL)
237 ····················{
238 ························if (field.Column.Size != 0)
239 ····························addColumnElement.Add( new XAttribute( "size", field.Column.Size.ToString() ) );
240 ····················}
241 ····················if (0 != field.Column.Precision && !field.Column.IgnoreColumnSizeInDDL)
242 ····················{
243 ························if (field.Column.Precision != 0)
244 ····························addColumnElement.Add( new XAttribute( "precision", field.Column.Precision.ToString() ) );
245 ····················}
246 ····················addColumnElement.Add( new XAttribute( "allowNull", field.Column.AllowDbNull.ToString() ) );····················
247 ················}
248 ················else if (isPrimary && dc.AutoIncrement)
249 ················{
250 ····················addColumnElement.Add( new XAttribute( "autoIncrement", "true" ) );····················
251 ················}
252 ············}············
253 ········}
254
255
256 ········protected Field FindField (string columnName, Class cl)
257 ········{
258 ············Field result = null;
259 ············foreach (Field field in cl.Fields)
260 ············{
261 ················if (field.Column.Name == columnName)
262 ················{
263 ····················result = field;
264 ····················break;
265 ················}
266 ············}
267 ············return result;
268 ········}
269
270
271 ········protected Class GetClassForTable(string tableName, NDOMapping mapping)
272 ········{
273 ············foreach(Class cl in mapping.Classes)
274 ················if (cl.TableName == tableName)
275 ····················return cl;
276 ············return null;
277 ········}
278
279 ····}
280 }
281
New Commit (273289e)
1 //
2 // Copyright (c) 2002-2022 Mirko Matytschak
3 // (www.netdataobjects.de)
4 //
5 // Author: Mirko Matytschak
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8 // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10 // Software, and to permit persons to whom the Software is furnished to do so, subject to the following
11 // conditions:
12
13 // The above copyright notice and this permission notice shall be included in all copies or substantial portions
14 // of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21
22
23 using System;
24 using System.IO;
25 using System.Data;
26 using System.Collections.Generic;
27 using System.Xml.Linq;
28 using NDO;
29 using NDO.Mapping;
30 using NDOInterfaces;
31 using System.Reflection;
32 using System.Text;
33 using System.Security.Cryptography;
34
35 namespace NDOEnhancer
36 {
37 ····/// <summary>
38 ····/// Zusammenfassung für SQLDiffGenerator.
39 ····/// </summary>
40 ····internal class NdoTransDiffGenerator
41 ····{
42 ········NDOMapping mappings;
43 ········MessageAdapter messages;
44 ········public void Generate(DataSet dsSchema, DataSet dsBak, string filename, NDOMapping mappings, MessageAdapter messages)
45 ········{
46 ············this.mappings = mappings;
47 ············this.messages = messages;
48
49 ············string diffFileName = filename.Replace(".ndo.sql", ".ndodiff." + mappings.SchemaVersion + ".xml");
50 ············bool isNewDiffFile = !File.Exists(diffFileName);
51 ············XElement rootElement = null;
 
52 ············if (isNewDiffFile)
53 ············{
54 ················rootElement = new XElement( "NdoSchemaTransitions" );
55 ················rootElement.Add( new XComment( "NDO accumulates all schema changes in this diff file. Note: If you change the mapping schema version, a new diff file will be created. You can change the mapping schema version in the NDO configuration dialog. Don't use the Mapping Tool to change the schema information, because it will be overwritten by the value set in the configuration. For automatic builds set the schema version value in the .ndoproj file." ) );
 
 
56 ············}
57 ············else
58 ············{
59 ················rootElement = XElement.Load( diffFileName );
 
 
 
 
 
 
 
 
 
 
60 ············}
61
62 XElement transElement = new XElement( "NdoSchemaTransition" ) ;
63 ············rootElement.Add( transElement );
64
65 ············if (GenerateInternal( dsSchema, dsBak, transElement ))
66 ············{
67 ················Guid g = MakeHash( transElement.ToString() );
68 ················transElement.SetAttributeValue( "id", g );
69 ················rootElement.Save( diffFileName );
70 ············}
71 ········}
72
73 ········public static Guid MakeHash( string input )
74 ········{
75 ············var buf = Encoding.UTF8.GetBytes(input);
76
77 ············using (var sha = SHA256.Create())
78 ············{
79 ················var hash = sha.ComputeHash( buf );
80 ················byte[] arr = new byte[16];
81 ················Array.Copy( hash, arr, 16 );
82 ················return new Guid( arr );
83 ············}
84 ········}
85
86 ········bool GenerateInternal(System.Data.DataSet dsNewSchema, System.Data.DataSet dsOldSchema, XElement transElement)
87 ········{
88 ············bool hasChanges = false;
89 ············foreach(DataTable dt in dsNewSchema.Tables)
90 ············{
91 ················if (!dsOldSchema.Tables.Contains(dt.TableName))
92 ················{
93 ····················transElement.Add( CreateTable( dt ) );
94 ····················hasChanges = true;
95 ················}
96 ················else
97 ················{
98 ····················DataTable dtOld = dsOldSchema.Tables[dt.TableName];
99 ····················List<DataColumn> addedColumns = new List<DataColumn>();
100 ····················List<DataColumn> removedColumns = new List<DataColumn>();
101 ····················List<DataColumn> changedColumns = new List<DataColumn>();
102 ····················foreach(DataColumn dc in dt.Columns)
103 ····················{
104 ························if (!dtOld.Columns.Contains(dc.ColumnName))
105 ························{
106 ····························addedColumns.Add(dc);
107 ························}
108 ························else
109 ························{
110 ····························DataColumn dcOld = dtOld.Columns[dc.ColumnName];
111 ····························if (dc.DataType != dcOld.DataType || dc.MaxLength != dcOld.MaxLength)
112 ································changedColumns.Add(dc);
113 ························}
114 ····················}
115 ····················foreach(DataColumn dc in dtOld.Columns)
116 ····················{
117 ························if (!dt.Columns.Contains(dc.ColumnName))
118 ························{
119 ····························removedColumns.Add(dc);
120 ························}
121 ····················}
122 ····················if (addedColumns.Count > 0 || removedColumns.Count > 0 || changedColumns.Count > 0)
123 ························hasChanges = true;
124
125 ····················if (!hasChanges)
126 ························continue;
127
128 ····················XElement changeTableElement = ChangeTable(dt, addedColumns, removedColumns, changedColumns);
129 ····················if (changeTableElement.HasElements)
130 ························transElement.Add( changeTableElement );
131
132 ················}
133 ············}
134
135 ············foreach (DataTable dt in dsOldSchema.Tables)
136 ············{
137 ················if (!dsNewSchema.Tables.Contains( dt.TableName ))
138 ················{
139 ····················XElement dropTableElement = new XElement( "DropTable", new XAttribute( "name", dt.TableName ) );
140 ····················transElement.Add( dropTableElement );
141 ····················hasChanges = true;
142 ················}
143 ············}
144
145 ············return hasChanges;
146 ········}
147
148 ········XElement ChangeTable(DataTable dt, List<DataColumn> addedColumns, List<DataColumn> removedColums, List<DataColumn> changedColumns)
149 ········{
150 ············XElement alterTableElement = new XElement( "AlterTable", new XAttribute( "name", dt.TableName ) );
151
152 ············foreach(DataColumn dc in addedColumns)
153 ············{
154 ················XElement addColumnElement = new XElement( "AddColumn", new XAttribute( "name", dc.ColumnName ) );
155 ················CreateColumn(addColumnElement, dc, GetClassForTable(dt.TableName, this.mappings), false);
156 ················alterTableElement.Add( addColumnElement );
157 ············}
158
159 ············foreach(DataColumn dc in removedColums)
160 ············{
161 ················XElement dropColumnElement = new XElement( "DropColumn", new XAttribute( "name", dc.ColumnName ) );
162 ················alterTableElement.Add( dropColumnElement );
163 ············}
164
165 ············foreach(DataColumn dc in changedColumns)
166 ············{
167 ················XElement alterColumnElement = new XElement( "AlterColumn", new XAttribute( "name", dc.ColumnName ) );
168 ················CreateColumn(alterColumnElement, dc, GetClassForTable(dt.TableName, this.mappings), false);
169 ················alterTableElement.Add( alterColumnElement );
170 ············}
171
172 ············if (removedColums.Count > 0)
173 ············{
174 ················alterTableElement.Add( new XComment( "If you need to rename a column use the following syntax:" ) );
175 ················alterTableElement.Add( new XComment( "<RenameColumn oldName=\"...\" newName=\"...\" />" ) );
176 ············}
177
178 ············return alterTableElement;············
179 ········}
180
181 ········protected XElement CreateTable(DataTable dt)
182 ········{
183 ············XElement createTableElement = new XElement( "CreateTable", new XAttribute( "name", dt.TableName ) );
184
185 ············Class cl = FindClass(dt.TableName, mappings);
186
187 ············DataColumn[] primaryKeyColumns = dt.PrimaryKey;
188 ············bool hasPrimaryKeyColumns = primaryKeyColumns.Length > 0;
189
190 ············for (int i = 0; i < dt.Columns.Count; i++)
191 ············{
192 ················System.Data.DataColumn dc = dt.Columns[i];
193
194 ················bool isPrimary = false;
195 ················foreach (DataColumn pkc in primaryKeyColumns)
196 ················{
197 ····················if (pkc.ColumnName == dc.ColumnName)
198 ····················{
199 ························isPrimary = true;
200 ························break;
201 ····················}
202 ················}
203
204 ················XElement createColumnElement = new XElement( "CreateColumn", new XAttribute( "name", dc.ColumnName ) );
205 ················CreateColumn(createColumnElement, dc, cl, isPrimary);
206 ················createTableElement.Add( createColumnElement );
207 ············}
208
209 ············return createTableElement;
210 ········}
211
212 ········protected NDO.Mapping.Class FindClass(string tableName, NDOMapping mappings)
213 ········{
214 ············Class result = null;
215 ············foreach(Class cl in mappings.Classes)
216 ············{
217 ················if (cl.TableName == tableName)
218 ················{
219 ····················result = cl;
220 ····················break;
221 ················}
222 ············}
223 ············return result;
224 ········}
225
226 ········protected void CreateColumn(XElement addColumnElement, DataColumn dc, Class cl, bool isPrimary)
227 ········{
228 ············Type t = dc.DataType;
229 ············addColumnElement.Add( new XAttribute( "type", t.FullName + "," + new AssemblyName( t.Assembly.FullName ).Name ) );
230
231 ············if (isPrimary)
232 ················addColumnElement.Add( new XAttribute( "isPrimary", "true" ) );
233
234 ············if (cl != null)
235 ············{
236 ················Field field = FindField(dc.ColumnName, cl);
237
238 ················if (null != field)
239 ················{
240 ····················if (0 != field.Column.Size && !field.Column.IgnoreColumnSizeInDDL)
241 ····················{
242 ························if (field.Column.Size != 0)
243 ····························addColumnElement.Add( new XAttribute( "size", field.Column.Size.ToString() ) );
244 ····················}
245 ····················if (0 != field.Column.Precision && !field.Column.IgnoreColumnSizeInDDL)
246 ····················{
247 ························if (field.Column.Precision != 0)
248 ····························addColumnElement.Add( new XAttribute( "precision", field.Column.Precision.ToString() ) );
249 ····················}
250 ····················addColumnElement.Add( new XAttribute( "allowNull", field.Column.AllowDbNull.ToString() ) );····················
251 ················}
252 ················else if (isPrimary && dc.AutoIncrement)
253 ················{
254 ····················addColumnElement.Add( new XAttribute( "autoIncrement", "true" ) );····················
255 ················}
256 ············}············
257 ········}
258
259
260 ········protected Field FindField (string columnName, Class cl)
261 ········{
262 ············Field result = null;
263 ············foreach (Field field in cl.Fields)
264 ············{
265 ················if (field.Column.Name == columnName)
266 ················{
267 ····················result = field;
268 ····················break;
269 ················}
270 ············}
271 ············return result;
272 ········}
273
274
275 ········protected Class GetClassForTable(string tableName, NDOMapping mapping)
276 ········{
277 ············foreach(Class cl in mapping.Classes)
278 ················if (cl.TableName == tableName)
279 ····················return cl;
280 ············return null;
281 ········}
282
283 ····}
284 }
285