Datei: NDODLL/SchemaTransitionGenerator.cs

Last Commit (0549873)
1 //
2 // Copyright (c) 2002-2024 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.Text;
25 using System.Collections.Generic;
26 using System.Data;
27 using System.Linq;
28 using System.Xml.Linq;
29 using NDO.Mapping;
30 using NDOInterfaces;
31 using NDO.ProviderFactory;
32
33 namespace NDO
34 {
35 ····/// <summary>
36 /// Zusammenfassung für GenericDiffGenerator.
37 ····/// </summary>
38 internal class SchemaTransitionGenerator
39 ····{
40 ········private readonly IProvider provider;
41 ········private readonly ISqlGenerator concreteGenerator;
42 ········private readonly NDOMapping mappings;
 
 
 
 
 
 
 
43 ········public SchemaTransitionGenerator( INDOProviderFactory providerFactory, string providerName, NDOMapping mappings )
44 ········{
45 ············this.provider = providerFactory[providerName];
46 ············this.concreteGenerator = providerFactory.Generators[providerName];
47 ············this.mappings = mappings;
48 ········}
49
 
 
 
 
 
50 ········public string Generate(XElement transElement)
51 ········{
52 ············StringBuilder sb = new StringBuilder();
53 ············foreach(XElement actionElement in transElement.Elements())
54 ············{
55 ················if (actionElement.Name == "DropTable")
56 ················{
57 ····················sb.Append( DropTable( actionElement ) );
58 ················}
59 else if ( actionElement. Name=="CreateTable")
60 ················{
61 ····················sb.Append( CreateTable( actionElement ) );
62 ················}
63 else if ( actionElement. Name=="AlterTable")
64 ················{
65 ····················sb.Append( ChangeTable( actionElement ) );
 
 
 
 
66 ················}
67
68 ············}
69 ············return sb.ToString();
70 ········}
71
72 ········string ChangeTable(XElement actionElement)
73 ········{
74 ············List<XElement> addedColumns = actionElement.Elements("AddColumn").ToList();
75 ············List<XElement> removedColumns = actionElement.Elements("DropColumn").ToList();
76 ············List<XElement> changedColumns = actionElement.Elements("AlterColumn").ToList();
77
78 ············if (addedColumns.Count == 0 && removedColumns.Count == 0 && changedColumns.Count == 0)
79 ················return String.Empty;
80
81 ············StringBuilder sb = new StringBuilder();
82
83 ············string rawTableName = actionElement.Attribute( "name" ).Value;
84 ············string tableName = this.provider.GetQualifiedTableName(rawTableName);
85 ············string alterString = "ALTER TABLE " + tableName + ' ';
86
87 ············foreach(XElement columnElement in addedColumns)
88 ············{
89 ················sb.Append(alterString);
90 ················sb.Append(concreteGenerator.AddColumn());
91 ················sb.Append(' ');
92 ················sb.Append(CreateColumn(columnElement, GetClassForTable(rawTableName, this.mappings), this.provider, false));
93 ················sb.Append(";\n");
94 ············}
95
96 ············foreach(XElement columnElement in removedColumns)
97 ············{
98 ················sb.Append(alterString);
99 ················sb.Append( concreteGenerator.RemoveColumn( provider.GetQuotedName( columnElement.Attribute( "name" ).Value ) ) );
100 ················sb.Append(";\n");
101 ············}
102
103 ············foreach(XElement columnElement in changedColumns)
104 ············{
105 ················sb.Append(alterString);
106 ················sb.Append(concreteGenerator.AlterColumnType());
107 ················sb.Append(' ');
108 ················sb.Append(CreateColumn(columnElement, GetClassForTable(rawTableName, this.mappings), this.provider, false));
109 ················sb.Append(";\n");
110 ············}
111
112 ············return sb.ToString();
113 ········}
114
115 ········string RenameColumn(string tableName, string oldColumn, string newColumn, string typeString)
116 ········{
117 ············string s = concreteGenerator.RenameColumn(tableName, oldColumn, newColumn, typeString);
118 ············
119 ············if (s != string.Empty)
120 ············return s;
121 ········
122 ············string alterString = "ALTER TABLE " + tableName + ' ';
123
124 ············StringBuilder sb = new StringBuilder(alterString);
125 ············sb.Append(concreteGenerator.AddColumn());
126 ············sb.Append(' ');
127 ············sb.Append(newColumn);
128 ············sb.Append(' ');
129 ············sb.Append(typeString);
130 ············sb.Append(";\n");
131
132 ············sb.Append("UPDATE ");
133 ············sb.Append(tableName);
134 ············sb.Append(" SET ");············
135 ············sb.Append(newColumn);
136 ············sb.Append(" = ");
137 ············sb.Append(oldColumn);
138 ············sb.Append(";\n");
139
140 ············sb.Append(alterString);
141 ············sb.Append(concreteGenerator.RemoveColumn(oldColumn));
142 ············sb.Append(';');
143 ············return sb.ToString();
144 ········}
145
146 ········protected string DropTable(XElement actionElement)
147 ········{
148 ············string tableName = this.provider .GetQualifiedTableName( actionElement.Attribute( "name" ).Value );
149 ············return concreteGenerator.DropTable( tableName );
150 ········}
151
152 ········protected string CreateTable(XElement actionElement)
153 ········{
154 ············StringBuilder sb = new StringBuilder();
155 ············IProvider provider = NDOProviderFactory.Instance[concreteGenerator.ProviderName];
156 ············if (provider == null)
157 ················throw new Exception("Can't find NDO provider '" + concreteGenerator.ProviderName + "'.");
158
159 ············string dtTableName = actionElement.Attribute( "name" ).Value;
160
161 ············string tableName = this.provider.GetQualifiedTableName( dtTableName );
162
163 ············Class cl = FindClass(dtTableName, mappings);
164
165 ············if (cl != null)
166 ············{
167 ················Connection conn = mappings.FindConnection(cl);
168 ················if (conn != null)
169 ····················concreteGenerator.ConnectToDatabase(conn.Name);
170 ············}
171
172 ············sb.Append(concreteGenerator.BeginnTable(tableName));
173 ············sb.Append('\n');
174
175 ············List<XElement> columnElements = actionElement.Elements( "CreateColumn" ).ToList();
176
177 ············int vorletzterIndex = columnElements.Count - 1;
178 ············List<XElement> primaryKeyColumns = columnElements.Where( e =>
179 ············{
180 ················XAttribute attr;
181 ················return (attr = e.Attribute( "isPrimary" )) != null && String.Compare( attr.Value, "true", true ) == 0;
182 ············} ).ToList();
183
184 ············bool hasPrimaryKeyColumns = primaryKeyColumns.Count > 0;
185
186 ············for (int i = 0; i < columnElements.Count; i++)
187 ············{
188 ················XElement columnElement = columnElements[i];
189 ················string columnName = columnElement.Attribute("name").Value;
190
191 ················bool isPrimary = primaryKeyColumns.Any( e => e.Attribute( "name" ).Value == columnName );
192
193 ················sb.Append(CreateColumn(columnElement, cl, provider, isPrimary));
194 ················if (i < vorletzterIndex)
195 ················{
196 ····················sb.Append(",");
197 ····················sb.Append('\n');
198 ················}
199 ············}
200
201 ············if(concreteGenerator.PrimaryConstraintPlacement == PrimaryConstraintPlacement.InTable
202 ················&& hasPrimaryKeyColumns)
203 ············{
204 ················sb.Append(",");
205 ················sb.Append('\n');
206 ············}
207
208 ············if (hasPrimaryKeyColumns && concreteGenerator.PrimaryConstraintPlacement == PrimaryConstraintPlacement.InTable)
209 ············{
210 ················sb.Append(CreatePrimaryKeyConstraint(primaryKeyColumns, dtTableName, provider));
211 ············}
212 ············else
213 ············{
214 ················sb.Append('\n');
215 ············}
216 ············sb.Append(concreteGenerator.EndTable(tableName));
217 ············sb.Append('\n');
218
219 ············//············CreateIndex(primaryKeyColumns, sb, dt, provider);
220
221 ············if (hasPrimaryKeyColumns && concreteGenerator.PrimaryConstraintPlacement == PrimaryConstraintPlacement.AfterTable)
222 ············{
223 ················sb.Append(CreatePrimaryKeyConstraint(primaryKeyColumns, dtTableName, provider));
224 ············}
225
226 ············sb.Append('\n');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
228 ············return sb.ToString();
229 ········}
230
231 ········protected NDO.Mapping.Class FindClass(string tableName, NDOMapping mappings)
232 ········{
233 ············Class result = null;
234 ············foreach(Class cl in mappings.Classes)
235 ············{
236 ················if (cl.TableName == tableName)
237 ················{
238 ····················result = cl;
239 ····················break;
240 ················}
241 ············}
242 ············return result;
243 ········}
244
245 ········static bool IsNumeric( Type type )
246 ········{
247 ············switch (Type.GetTypeCode( type ))
248 ············{
249 ················case TypeCode.Byte:
250 ················case TypeCode.SByte:
251 ················case TypeCode.UInt16:
252 ················case TypeCode.UInt32:
253 ················case TypeCode.UInt64:
254 ················case TypeCode.Int16:
255 ················case TypeCode.Int32:
256 ················case TypeCode.Int64:
257 ················case TypeCode.Decimal:
258 ················case TypeCode.Double:
259 ················case TypeCode.Single:
260 ····················return true;
261 ················case TypeCode.Object:
262 ····················if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof( Nullable<> ))
263 ····················{
264 ························return IsNumeric(Nullable.GetUnderlyingType( type ));
265 ····················}
266 ····················return false;
267 ················default:
268 ····················return false;
269 ············}
270 ········}
271
272 ········protected string CreateColumn(XElement columnElement, Class cl, IProvider provider, bool isPrimary)
273 ········{
274 ············string rawName = columnElement.Attribute( "name" ).Value;
275 ············Type dcDataType = Type.GetType( columnElement.Attribute( "type" ).Value );
276 ············string name = provider.GetQuotedName(rawName);
277 ············string columnType = columnElement.Attribute( "dbtype" )?.Value;
278 ············if (columnType == String.Empty)··// Make sure the column type will be infered, if it is an empty string
279 ················columnType = null;
280 ············string width = columnElement.Attribute("size") == null ? null : columnElement.Attribute("size").Value;
281 ············string precision = null;
282 ············bool autoIncrement = false;
283 ············StringBuilder sb = new StringBuilder();
284 ············bool allowNull = true;
285 ············string defaultValue = columnElement.Attribute( "default" )?.Value;
286
287 ············if (cl != null)
288 ············{
289 ················Field field = FindField(rawName, cl);
290
291 ················if (null != field)
292 ················{
293 ····················if ( !String.IsNullOrEmpty(columnType) && null != field.Column.DbType)
294 ························columnType = field.Column.DbType;
295 ····················if (0 != field.Column.Size && !field.Column.IgnoreColumnSizeInDDL)
296 ····················{
297 ························int dl = field.Column.Size;
298 ························if (dl == -1)
299 ····························width = "max";
300 ························else
301 ····························width = dl.ToString();
302 ····················}
303 ····················if (0 != field.Column.Precision && !field.Column.IgnoreColumnSizeInDDL)
304 ························precision = field.Column.Precision.ToString();
305 ····················allowNull = field.Column.AllowDbNull;
306 ················}
307 ················else if (cl.TimeStampColumn == rawName)
308 ················{
309 ····················if (!provider.SupportsNativeGuidType)
310 ························width = "36";
311 ················}
312 ················else if (isPrimary && columnElement.Attribute( "autoIncrement" ) != null && String.Compare(columnElement.Attribute( "autoIncrement" ).Value, "true", true) == 0)
313 ················{
314 ····················autoIncrement = true;
315 ················}
316 ············}
317 ············if (null == columnType)
318 ············{
319 ················try
320 ················{
321 ····················columnType = concreteGenerator.DbTypeFromType(dcDataType);
322 ················}
323 ················catch
324 ················{
325 ····················System.Diagnostics.Debug.Write("");
326 ················}
327 ············}
328
329 ············if (null == width)
330 ············{
331 ················int dl = provider.GetDefaultLength(dcDataType);
332 ················if (dl != 0)
333 ················{
334 ····················if (dl == -1)
335 ························width = "max";
336 ····················else
337 ························width = dl.ToString();
338 ················}
339 ············}
340 ············
341 ············// Because there is no GetDefaultPrecision in the provider...
342 ············// We assume the field to represent currency data
343 ············if (precision == null && dcDataType == typeof(decimal))
344 ············{
345 ················precision = "2";
346 ············}
347
348 ············if (columnType != null)
349 ············{
350 ················if (!concreteGenerator.LengthAllowed(columnType))
351 ····················width = null;
352 ············}
353 ············else
354 ············{
355 ················if (!concreteGenerator.LengthAllowed(dcDataType))
356 ····················width = null;
357 ············}
358
359
360 ············if (autoIncrement && concreteGenerator.HasSpecialAutoIncrementColumnFormat)
361 ················sb.Append(concreteGenerator.AutoIncrementColumn(name, dcDataType, columnType, width, isPrimary));
362 ············else if(isPrimary && concreteGenerator.PrimaryConstraintPlacement == PrimaryConstraintPlacement.InColumn)
363 ················sb.Append(concreteGenerator.PrimaryKeyColumn(name, dcDataType, columnType, width));
364 ············else if (width != null && precision != null)
365 ················sb.Append(name + " " + columnType + "(" + width + "," + precision + ")");
366 ············else if (width != null)
367 ················sb.Append(name + " " + columnType + "(" + width + ")");············
368 ············else
369 ················sb.Append(name + " " + columnType);
370
371 ············sb.Append(" ");
372
373 ············if (defaultValue != null)
374 ············{
375 ················sb.Append( "DEFAULT " );
376 ················if (IsNumeric( dcDataType ))
377 ····················sb.Append( defaultValue);
378 ················else
379 ················{
380 ····················sb.Append( '\'' );
381 ····················sb.Append( defaultValue.Replace( "'", "''" ) );
382 ····················sb.Append( '\'' );
383 ················}
384 ················sb.Append( ' ' );
385 ············}
386
387 ············sb.Append( concreteGenerator.NullExpression( allowNull && columnElement.Attribute( "allowNull" ) != null && String.Compare( columnElement.Attribute( "allowNull" ).Value, "true", true ) == 0 ) );
388 ············return sb.ToString();
389 ········}
390
391 ········protected string CreatePrimaryKeyConstraint(List<XElement> primaryKeyColumns, string tableName, IProvider provider)
392 ········{
393 ············if (primaryKeyColumns.Count == 0)
394 ················return string.Empty;
395 ············string[] strArr = tableName.Split('.');
396 ············string constraintName = provider.GetQuotedName("PK_" + strArr[strArr.Length - 1]);
397 ············DataColumn[] pkColumns = (from pk in primaryKeyColumns select new DataColumn( pk.Attribute( "name" ).Value )).ToArray();
398 ············return concreteGenerator.CreatePrimaryKeyConstraint(pkColumns, constraintName, provider.GetQualifiedTableName(tableName)) + '\n';
399 ········}
400
401 ········protected Field FindField (string columnName, Class cl)
402 ········{
403 ············Field result = null;
404 ············foreach (Field field in cl.Fields)
405 ············{
406 ················if (field.Column.Name == columnName)
407 ················{
408 ····················result = field;
409 ····················break;
410 ················}
411 ············}
412 ············return result;
413 ········}
414
415 ········protected Class GetClassForTable(string tableName, NDOMapping mapping)
416 ········{
417 ············foreach(Class cl in mapping.Classes)
418 ················if (cl.TableName == tableName)
419 ····················return cl;
420 ············return null;
421 ········}
422 ····}
423 }
424
New Commit (e9b343b)
1 //
2 // Copyright (c) 2002-2024 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.Text;
25 using System.Collections.Generic;
26 using System.Data;
27 using System.Linq;
28 using System.Xml.Linq;
29 using NDO.Mapping;
30 using NDOInterfaces;
31 using NDO.ProviderFactory;
32
33 namespace NDO
34 {
35 ····/// <summary>
36 /// The SchemaTransitionGenerator class transforms an Xml description to SQL DDL statements for a concrete Database.
37 ····/// </summary>
38 public class SchemaTransitionGenerator
39 ····{
40 ········private readonly IProvider provider;
41 ········private readonly ISqlGenerator concreteGenerator;
42 ········private readonly NDOMapping mappings;
43
44 ········/// <summary>
45 ········/// SchemaTransitionGenerator constructor
46 ········/// </summary>
47 ········/// <param name="providerFactory">Factory to get the concrete provider for the database.</param>
48 ········/// <param name="providerName">The name of the concrete provider.</param>
49 ········/// <param name="mappings">The mapping information of the current application.</param>
50 ········public SchemaTransitionGenerator( INDOProviderFactory providerFactory, string providerName, NDOMapping mappings )
51 ········{
52 ············this.provider = providerFactory[providerName];
53 ············this.concreteGenerator = providerFactory.Generators[providerName];
54 ············this.mappings = mappings;
55 ········}
56
57 ········/// <summary>
58 ········/// Transforms an Xml description to SQL DDL statements for a concrete Database.
59 ········/// </summary>
60 ········/// <param name="transElement"></param>
61 ········/// <returns></returns>
62 ········public string Generate(XElement transElement)
63 ········{
64 ············StringBuilder sb = new StringBuilder();
65 ············foreach(XElement actionElement in transElement.Elements())
66 ············{
67 ················if (actionElement.Name == "DropTable")
68 ················{
69 ····················sb.Append( DropTable( actionElement ) );
70 ················}
71 else if ( actionElement. Name == "CreateTable")
72 ················{
73 ····················sb.Append( CreateTable( actionElement ) );
74 ················}
75 else if ( actionElement. Name == "AlterTable")
76 ················{
77 ····················sb.Append( ChangeTable( actionElement ) );
78 ················}
79 ················else if (actionElement.Name == "CreateIndex")
80 ················{
81 ····················sb.Append( CreateIndex( actionElement ) );
82 ················}
 
83 ············}
84 ············return sb.ToString();
85 ········}
86
87 ········string ChangeTable(XElement actionElement)
88 ········{
89 ············List<XElement> addedColumns = actionElement.Elements("AddColumn").ToList();
90 ············List<XElement> removedColumns = actionElement.Elements("DropColumn").ToList();
91 ············List<XElement> changedColumns = actionElement.Elements("AlterColumn").ToList();
92
93 ············if (addedColumns.Count == 0 && removedColumns.Count == 0 && changedColumns.Count == 0)
94 ················return String.Empty;
95
96 ············StringBuilder sb = new StringBuilder();
97
98 ············string rawTableName = actionElement.Attribute( "name" ).Value;
99 ············string tableName = this.provider.GetQualifiedTableName(rawTableName);
100 ············string alterString = "ALTER TABLE " + tableName + ' ';
101
102 ············foreach(XElement columnElement in addedColumns)
103 ············{
104 ················sb.Append(alterString);
105 ················sb.Append(concreteGenerator.AddColumn());
106 ················sb.Append(' ');
107 ················sb.Append(CreateColumn(columnElement, GetClassForTable(rawTableName, this.mappings), this.provider, false));
108 ················sb.Append(";\n");
109 ············}
110
111 ············foreach(XElement columnElement in removedColumns)
112 ············{
113 ················sb.Append(alterString);
114 ················sb.Append( concreteGenerator.RemoveColumn( provider.GetQuotedName( columnElement.Attribute( "name" ).Value ) ) );
115 ················sb.Append(";\n");
116 ············}
117
118 ············foreach(XElement columnElement in changedColumns)
119 ············{
120 ················sb.Append(alterString);
121 ················sb.Append(concreteGenerator.AlterColumnType());
122 ················sb.Append(' ');
123 ················sb.Append(CreateColumn(columnElement, GetClassForTable(rawTableName, this.mappings), this.provider, false));
124 ················sb.Append(";\n");
125 ············}
126
127 ············return sb.ToString();
128 ········}
129
130 ········string RenameColumn(string tableName, string oldColumn, string newColumn, string typeString)
131 ········{
132 ············string s = concreteGenerator.RenameColumn(tableName, oldColumn, newColumn, typeString);
133 ············
134 ············if (s != string.Empty)
135 ············return s;
136 ········
137 ············string alterString = "ALTER TABLE " + tableName + ' ';
138
139 ············StringBuilder sb = new StringBuilder(alterString);
140 ············sb.Append(concreteGenerator.AddColumn());
141 ············sb.Append(' ');
142 ············sb.Append(newColumn);
143 ············sb.Append(' ');
144 ············sb.Append(typeString);
145 ············sb.Append(";\n");
146
147 ············sb.Append("UPDATE ");
148 ············sb.Append(tableName);
149 ············sb.Append(" SET ");············
150 ············sb.Append(newColumn);
151 ············sb.Append(" = ");
152 ············sb.Append(oldColumn);
153 ············sb.Append(";\n");
154
155 ············sb.Append(alterString);
156 ············sb.Append(concreteGenerator.RemoveColumn(oldColumn));
157 ············sb.Append(';');
158 ············return sb.ToString();
159 ········}
160
161 ········protected string DropTable(XElement actionElement)
162 ········{
163 ············string tableName = this.provider .GetQualifiedTableName( actionElement.Attribute( "name" ).Value );
164 ············return concreteGenerator.DropTable( tableName );
165 ········}
166
167 ········protected string CreateTable(XElement actionElement)
168 ········{
169 ············StringBuilder sb = new StringBuilder();
170 ············IProvider provider = NDOProviderFactory.Instance[concreteGenerator.ProviderName];
171 ············if (provider == null)
172 ················throw new Exception("Can't find NDO provider '" + concreteGenerator.ProviderName + "'.");
173
174 ············string dtTableName = actionElement.Attribute( "name" ).Value;
175
176 ············string tableName = this.provider.GetQualifiedTableName( dtTableName );
177
178 ············Class cl = FindClass(dtTableName, mappings);
179
180 ············if (cl != null)
181 ············{
182 ················Connection conn = mappings.FindConnection(cl);
183 ················if (conn != null)
184 ····················concreteGenerator.ConnectToDatabase(conn.Name);
185 ············}
186
187 ············sb.Append(concreteGenerator.BeginnTable(tableName));
188 ············sb.Append('\n');
189
190 ············List<XElement> columnElements = actionElement.Elements( "CreateColumn" ).ToList();
191
192 ············int vorletzterIndex = columnElements.Count - 1;
193 ············List<XElement> primaryKeyColumns = columnElements.Where( e =>
194 ············{
195 ················XAttribute attr;
196 ················return (attr = e.Attribute( "isPrimary" )) != null && String.Compare( attr.Value, "true", true ) == 0;
197 ············} ).ToList();
198
199 ············bool hasPrimaryKeyColumns = primaryKeyColumns.Count > 0;
200
201 ············for (int i = 0; i < columnElements.Count; i++)
202 ············{
203 ················XElement columnElement = columnElements[i];
204 ················string columnName = columnElement.Attribute("name").Value;
205
206 ················bool isPrimary = primaryKeyColumns.Any( e => e.Attribute( "name" ).Value == columnName );
207
208 ················sb.Append(CreateColumn(columnElement, cl, provider, isPrimary));
209 ················if (i < vorletzterIndex)
210 ················{
211 ····················sb.Append(",");
212 ····················sb.Append('\n');
213 ················}
214 ············}
215
216 ············if(concreteGenerator.PrimaryConstraintPlacement == PrimaryConstraintPlacement.InTable
217 ················&& hasPrimaryKeyColumns)
218 ············{
219 ················sb.Append(",");
220 ················sb.Append('\n');
221 ············}
222
223 ············if (hasPrimaryKeyColumns && concreteGenerator.PrimaryConstraintPlacement == PrimaryConstraintPlacement.InTable)
224 ············{
225 ················sb.Append(CreatePrimaryKeyConstraint(primaryKeyColumns, dtTableName, provider));
226 ············}
227 ············else
228 ············{
229 ················sb.Append('\n');
230 ············}
231 ············sb.Append(concreteGenerator.EndTable(tableName));
232 ············sb.Append('\n');
233
234 ············//············CreateIndex(primaryKeyColumns, sb, dt, provider);
235
236 ············if (hasPrimaryKeyColumns && concreteGenerator.PrimaryConstraintPlacement == PrimaryConstraintPlacement.AfterTable)
237 ············{
238 ················sb.Append(CreatePrimaryKeyConstraint(primaryKeyColumns, dtTableName, provider));
239 ············}
240
241 ············sb.Append('\n');
242
243 ············return sb.ToString();
244 ········}
245
246 ········string CreateIndex(XElement actionElement)
247 ········{
248 ············//<CreateIndex name="xxx" unique="True|False" fulltext="True|False" onTable="TableName">
249 ············//··<Column name="xxx" desc="True|False">
250 ············//</CreateIndex>
251 ············StringBuilder sb = new StringBuilder();
252 ············IProvider provider = NDOProviderFactory.Instance[concreteGenerator.ProviderName];
253 ············if (provider == null)
254 ················throw new Exception( "Can't find NDO provider '" + concreteGenerator.ProviderName + "'." );
255
256 ············string tableName··= this.provider.GetQualifiedTableName( actionElement.Attribute( "onTable" ).Value );
257 ············string indexName = this.provider.GetQualifiedTableName( actionElement.Attribute( "name" ).Value );
258
259 ············sb.Append( "CREATE " );
260
261 ············// NDO doesn't check, if these keywords are supported by the database.
262 ············if (String.Compare( actionElement.Attribute( "unique" )?.Value, "true", true ) == 0)
263 ················sb.Append( "UNIQUE " );
264 ············if (String.Compare( actionElement.Attribute( "fulltext" )?.Value, "true", true ) == 0)
265 ················sb.Append( "FULLTEXT " );
266
267 ············sb.Append( "INDEX " );
268 ············sb.Append( indexName );
269 ············sb.Append( " ON " );
270 ············sb.Append( tableName );
271 ············sb.Append( " (" );
272
273 ············var columns = actionElement.Elements( "Column" ).ToList();
274
275 ············var lastIndex = columns.Count - 1;
276 ············for (int i = 0; i <= lastIndex; i++)
277 ············{
278 ················var columnElement = columns[i];
279 ················var columnName = provider.GetQuotedName( columnElement.Attribute( "name" )?.Value );
280 ················
281 ················if (columnName == null)
282 ····················throw new Exception( "Column element of CreateIndex needs a name attribute" );
283
284 ················sb.Append( columnName );
285 ················
286 ················// NDO doesn't check, if DESC is supported by the database.
287 ················// We also assume, that ASC is the standard case, so we don't emit the ASC keyword.
288 ················var desc = String.Compare( columnElement.Attribute( "desc" )?.Value, "true", true ) == 0;
289 ················if (desc)
290 ····················sb.Append( " DESC" );
291
292 ················if (i < lastIndex)
293 ····················sb.Append( ", " );
294 ············}
295
296 ············sb.Append( ")" );
297
298 ············return sb.ToString();
299 ········}
300
301 ········protected NDO.Mapping.Class FindClass(string tableName, NDOMapping mappings)
302 ········{
303 ············Class result = null;
304 ············foreach(Class cl in mappings.Classes)
305 ············{
306 ················if (cl.TableName == tableName)
307 ················{
308 ····················result = cl;
309 ····················break;
310 ················}
311 ············}
312 ············return result;
313 ········}
314
315 ········static bool IsNumeric( Type type )
316 ········{
317 ············switch (Type.GetTypeCode( type ))
318 ············{
319 ················case TypeCode.Byte:
320 ················case TypeCode.SByte:
321 ················case TypeCode.UInt16:
322 ················case TypeCode.UInt32:
323 ················case TypeCode.UInt64:
324 ················case TypeCode.Int16:
325 ················case TypeCode.Int32:
326 ················case TypeCode.Int64:
327 ················case TypeCode.Decimal:
328 ················case TypeCode.Double:
329 ················case TypeCode.Single:
330 ····················return true;
331 ················case TypeCode.Object:
332 ····················if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof( Nullable<> ))
333 ····················{
334 ························return IsNumeric(Nullable.GetUnderlyingType( type ));
335 ····················}
336 ····················return false;
337 ················default:
338 ····················return false;
339 ············}
340 ········}
341
342 ········protected string CreateColumn(XElement columnElement, Class cl, IProvider provider, bool isPrimary)
343 ········{
344 ············string rawName = columnElement.Attribute( "name" ).Value;
345 ············Type dcDataType = Type.GetType( columnElement.Attribute( "type" ).Value );
346 ············string name = provider.GetQuotedName(rawName);
347 ············string columnType = columnElement.Attribute( "dbtype" )?.Value;
348 ············if (columnType == String.Empty)··// Make sure the column type will be infered, if it is an empty string
349 ················columnType = null;
350 ············string width = columnElement.Attribute("size") == null ? null : columnElement.Attribute("size").Value;
351 ············string precision = null;
352 ············bool autoIncrement = false;
353 ············StringBuilder sb = new StringBuilder();
354 ············bool allowNull = true;
355 ············string defaultValue = columnElement.Attribute( "default" )?.Value;
356
357 ············if (cl != null)
358 ············{
359 ················Field field = FindField(rawName, cl);
360
361 ················if (null != field)
362 ················{
363 ····················if ( !String.IsNullOrEmpty(columnType) && null != field.Column.DbType)
364 ························columnType = field.Column.DbType;
365 ····················if (0 != field.Column.Size && !field.Column.IgnoreColumnSizeInDDL)
366 ····················{
367 ························int dl = field.Column.Size;
368 ························if (dl == -1)
369 ····························width = "max";
370 ························else
371 ····························width = dl.ToString();
372 ····················}
373 ····················if (0 != field.Column.Precision && !field.Column.IgnoreColumnSizeInDDL)
374 ························precision = field.Column.Precision.ToString();
375 ····················allowNull = field.Column.AllowDbNull;
376 ················}
377 ················else if (cl.TimeStampColumn == rawName)
378 ················{
379 ····················if (!provider.SupportsNativeGuidType)
380 ························width = "36";
381 ················}
382 ················else if (isPrimary && columnElement.Attribute( "autoIncrement" ) != null && String.Compare(columnElement.Attribute( "autoIncrement" ).Value, "true", true) == 0)
383 ················{
384 ····················autoIncrement = true;
385 ················}
386 ············}
387 ············if (null == columnType)
388 ············{
389 ················try
390 ················{
391 ····················columnType = concreteGenerator.DbTypeFromType(dcDataType);
392 ················}
393 ················catch
394 ················{
395 ····················System.Diagnostics.Debug.Write("");
396 ················}
397 ············}
398
399 ············if (null == width)
400 ············{
401 ················int dl = provider.GetDefaultLength(dcDataType);
402 ················if (dl != 0)
403 ················{
404 ····················if (dl == -1)
405 ························width = "max";
406 ····················else
407 ························width = dl.ToString();
408 ················}
409 ············}
410 ············
411 ············// Because there is no GetDefaultPrecision in the provider...
412 ············// We assume the field to represent currency data
413 ············if (precision == null && dcDataType == typeof(decimal))
414 ············{
415 ················precision = "2";
416 ············}
417
418 ············if (columnType != null)
419 ············{
420 ················if (!concreteGenerator.LengthAllowed(columnType))
421 ····················width = null;
422 ············}
423 ············else
424 ············{
425 ················if (!concreteGenerator.LengthAllowed(dcDataType))
426 ····················width = null;
427 ············}
428
429
430 ············if (autoIncrement && concreteGenerator.HasSpecialAutoIncrementColumnFormat)
431 ················sb.Append(concreteGenerator.AutoIncrementColumn(name, dcDataType, columnType, width, isPrimary));
432 ············else if(isPrimary && concreteGenerator.PrimaryConstraintPlacement == PrimaryConstraintPlacement.InColumn)
433 ················sb.Append(concreteGenerator.PrimaryKeyColumn(name, dcDataType, columnType, width));
434 ············else if (width != null && precision != null)
435 ················sb.Append(name + " " + columnType + "(" + width + "," + precision + ")");
436 ············else if (width != null)
437 ················sb.Append(name + " " + columnType + "(" + width + ")");············
438 ············else
439 ················sb.Append(name + " " + columnType);
440
441 ············sb.Append(" ");
442
443 ············if (defaultValue != null)
444 ············{
445 ················sb.Append( "DEFAULT " );
446 ················if (IsNumeric( dcDataType ))
447 ····················sb.Append( defaultValue);
448 ················else
449 ················{
450 ····················sb.Append( '\'' );
451 ····················sb.Append( defaultValue.Replace( "'", "''" ) );
452 ····················sb.Append( '\'' );
453 ················}
454 ················sb.Append( ' ' );
455 ············}
456
457 ············sb.Append( concreteGenerator.NullExpression( allowNull && columnElement.Attribute( "allowNull" ) != null && String.Compare( columnElement.Attribute( "allowNull" ).Value, "true", true ) == 0 ) );
458 ············return sb.ToString();
459 ········}
460
461 ········protected string CreatePrimaryKeyConstraint(List<XElement> primaryKeyColumns, string tableName, IProvider provider)
462 ········{
463 ············if (primaryKeyColumns.Count == 0)
464 ················return string.Empty;
465 ············string[] strArr = tableName.Split('.');
466 ············string constraintName = provider.GetQuotedName("PK_" + strArr[strArr.Length - 1]);
467 ············DataColumn[] pkColumns = (from pk in primaryKeyColumns select new DataColumn( pk.Attribute( "name" ).Value )).ToArray();
468 ············return concreteGenerator.CreatePrimaryKeyConstraint(pkColumns, constraintName, provider.GetQualifiedTableName(tableName)) + '\n';
469 ········}
470
471 ········protected Field FindField (string columnName, Class cl)
472 ········{
473 ············Field result = null;
474 ············foreach (Field field in cl.Fields)
475 ············{
476 ················if (field.Column.Name == columnName)
477 ················{
478 ····················result = field;
479 ····················break;
480 ················}
481 ············}
482 ············return result;
483 ········}
484
485 ········protected Class GetClassForTable(string tableName, NDOMapping mapping)
486 ········{
487 ············foreach(Class cl in mapping.Classes)
488 ················if (cl.TableName == tableName)
489 ····················return cl;
490 ············return null;
491 ········}
492 ····}
493 }
494