Datei: NDOEnhancer/Enhancer/Enhancer.cs
Last Commit (c39bd40)
1 | // |
2 | // Copyright (c) 2002-2016 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.RegularExpressions; |
25 | using System.IO; |
26 | using System.Diagnostics; |
27 | using System.Collections; |
28 | using System.Collections.Generic; |
29 | using System.Linq; |
30 | using System.Xml; |
31 | using System.Data; |
32 | using Microsoft.Win32; |
33 | |
34 | using NDO; |
35 | using NDO.Mapping; |
36 | using NDO.Mapping.Attributes; |
37 | |
38 | using ILCode; |
39 | using System.Reflection; |
40 | |
41 | |
42 | namespace NDOEnhancer |
43 | { |
44 | ····/// <summary> |
45 | ····/// Der ganze Enhancement-Prozess beginnt bei DoIt() |
46 | ····/// </summary> |
47 | ····internal class Enhancer |
48 | ····{ |
49 | ········public |
50 | ············Enhancer( ProjectDescription projectDescription, MessageAdapter messages ) |
51 | ········{ |
52 | ············this.projectDescription····= projectDescription; |
53 | ············this.debug········= projectDescription.Debug; |
54 | ············this.binFile····= projectDescription.BinFile; |
55 | ············this.objPath····= projectDescription.ObjPath; |
56 | ············this.messages····= messages; |
57 | |
58 | ············binPdbFile = Path.Combine(Path.GetDirectoryName( binFile ), Path.GetFileNameWithoutExtension( binFile ) + ".pdb"); |
59 | ············tempDir = Path.Combine(objPath, "ndotemp"); |
60 | ············if (!Directory.Exists(tempDir)) |
61 | ················Directory.CreateDirectory(tempDir); |
62 | ············string fileWithoutExtension = Path.GetFileNameWithoutExtension(binFile); |
63 | ············ilFileName···· = Path.Combine(tempDir, fileWithoutExtension + ".org.il"); |
64 | ············resFile = Path.Combine(tempDir, fileWithoutExtension + ".org.res"); |
65 | ············resEnhFile = Path.Combine(tempDir, fileWithoutExtension + ".res"); |
66 | ············ilEnhFile = Path.Combine(tempDir, fileWithoutExtension + ".il"); |
67 | ············objFile = Path.Combine(objPath, Path.GetFileName(binFile)); |
68 | ············enhFile = Path.Combine(tempDir, Path.GetFileName(binFile)); |
69 | ············enhPdbFile = Path.Combine(tempDir, fileWithoutExtension + ".pdb"); |
70 | ············projPath = projectDescription.ProjPath; |
71 | ············schemaFile = Path.Combine(Path.GetDirectoryName(binFile), fileWithoutExtension + ".ndo.xsd"); |
72 | ············mappingDestFile = Path.Combine(Path.GetDirectoryName( binFile ), projectDescription.ConfigurationOptions.TargetMappingFileName); |
73 | ············mappingFile = projectDescription.DefaultMappingFileName; |
74 | ············options = projectDescription.ConfigurationOptions; |
75 | |
76 | ············//············foreach (EnvDTE.Property p in project.Properties) |
77 | ············//················messages.WriteLine("··" + p.Name + " " + p.Value.ToString()); |
78 | |
79 | ········} |
80 | |
81 | ········private ProjectDescription····projectDescription; |
82 | ········private bool················debug; |
83 | ········private bool················isEnhanced; |
84 | ········private bool················verboseMode; |
85 | ········private string················oidTypeName = null; |
86 | ········private bool················hasPersistentClasses; |
87 | ········private string················binFile; |
88 | ········private string················binPdbFile; |
89 | ········private string················objPath; |
90 | ········private string··············tempDir; |
91 | ········private string··············projPath; |
92 | |
93 | ········private string················ilFileName; |
94 | ········private string················resFile; |
95 | ········private string··············resEnhFile; |
96 | ········private string··············ilEnhFile; |
97 | ········private string················objFile; |
98 | ········private string················enhFile; |
99 | ········private string················enhPdbFile; |
100 | ········private string················schemaFile; |
101 | ········private string················mappingDestFile; |
102 | ········private string················mappingFile; |
103 | ········private string················ownAssemblyName = null; |
104 | ········private StreamWriter········sortedFieldsFile; |
105 | |
106 | ········private ClassHashtable········allPersistentClasses = new ClassHashtable(); |
107 | ········private Hashtable············allSortedFields = new ClassHashtable(); |
108 | ········private Hashtable············allReferences = new ClassHashtable(); |
109 | ········private Hashtable············assemblyFullNames = new Hashtable(); |
110 | ········private IList················tabuClasses = new ArrayList(); |
111 | ········private NDOMapping··········mappings; |
112 | ········private MessageAdapter········messages; |
113 | ········private NDODataSet············dsSchema; |
114 | ········private ConfigurationOptions options; |
115 | ········private string················assemblyKeyFile = null; |
116 | |
117 | ········private static string assemblyPath = null; |
118 | |
119 | |
120 | ········public static string AssemblyPath |
121 | ········{ |
122 | ············get |
123 | ············{ |
124 | ················if (null == assemblyPath) |
125 | ················{ |
126 | ····················RegistryKey key = Registry.LocalMachine.OpenSubKey( @"SOFTWARE\NDO" ); |
127 | ····················if ( key == null ) |
128 | ························throw new Exception( @"Can't find NDO in the registry at HKLM\SOFTWARE\NDO. Please reinstall NDO." ); |
129 | ····················assemblyPath = (string) key.GetValue( "InstallDir" ); |
130 | ····················if ( assemblyPath == null ) |
131 | ························throw new Exception( @"Can't find InstallDir value in the registry at HKLM\SOFTWARE\NDO. Please reinstall NDO." ); |
132 | ················} |
133 | ················return assemblyPath; |
134 | ············} |
135 | ········} |
136 | |
137 | ········void CheckNDO(Assembly ass) |
138 | ········{ |
139 | ·· //········ AssemblyName[] references = ass.GetReferencedAssemblies(); |
140 | ·· //········ NDOAssemblyName refAn = null; |
141 | ·· //········ foreach (AssemblyName an in references) |
142 | ·· //········ { |
143 | ·· //············ if (an.Name == "NDO") |
144 | ·· //················ refAn = new NDOAssemblyName(an.FullName); |
145 | ············//} |
146 | ·· //········ if (refAn == null) |
147 | ·· //············ return; |
148 | ·· //········ NDOAssemblyName ndoAn = new NDOAssemblyName(typeof(NDOPersistentAttribute).Assembly.FullName);··// give us the NDO version the enhancer belongs to |
149 | ············//Version refVersion = refAn.AssemblyVersion; |
150 | ············//bool isRightVersion = refVersion.Major > 2 || refVersion.Major == 2 && refVersion.Minor >= 1; |
151 | ·· //········ if (refAn.PublicKeyToken != ndoAn.PublicKeyToken || !isRightVersion) |
152 | ·· //········ { |
153 | ·· //············ throw new Exception("Assembly " + ass.FullName + " references a wrong NDO.dll. Expected: " + ndoAn.FullName + ". Found: " + refAn.FullName + "."); |
154 | ·· //········ }·· |
155 | ········} |
156 | |
157 | |
158 | ········private void |
159 | ············searchPersistentBases() |
160 | ········{ |
161 | ············Dictionary<string, NDOReference> references = projectDescription.References; |
162 | ············ArrayList ownClassList = null; |
163 | ············string binaryAssemblyFullName = null; |
164 | |
165 | ············if (!projectDescription.IsWebProject) |
166 | ············{ |
167 | ················// Check, if we can load the project bin file. |
168 | ················try |
169 | ················{ |
170 | ····················binaryAssemblyFullName = NDOAssemblyChecker.GetAssemblyName(this.binFile); |
171 | ················} |
172 | ················catch (Exception ex) |
173 | ················{ |
174 | ····················throw new Exception("Can't load referenced Assembly '" + this.binFile + ". " + ex.Message); |
175 | ················} |
176 | ············} |
177 | |
178 | ············// Durchsuche alle referenzierten Assemblies |
179 | ············foreach (NDOReference reference in references.Values) |
180 | ············{ |
181 | ················if ( !reference.CheckThisDLL ) |
182 | ····················continue; |
183 | |
184 | ················string dllPath = reference.Path; |
185 | ················bool ownAssembly = (string.Compare( dllPath, this.binFile, true ) == 0); |
186 | |
187 | ················if (!ownAssembly && !NDOAssemblyChecker.IsEnhanced( dllPath )) |
188 | ····················continue; |
189 | |
190 | ················AssemblyName assToLoad = null; |
191 | ················Assembly ass = null; |
192 | ················try |
193 | ················{ |
194 | ····················if (verboseMode) |
195 | ························messages.WriteLine($"Loading assembly {dllPath}"); |
196 | ····················assToLoad = AssemblyName.GetAssemblyName(dllPath); |
197 | ····················ass = Assembly.Load(assToLoad); |
198 | ················} |
199 | ················catch (Exception ex) |
200 | ················{ |
201 | ····················if (assToLoad != null && (binaryAssemblyFullName == null || string.Compare(binaryAssemblyFullName, assToLoad.FullName, true) != 0)) |
202 | ····················{ |
203 | ························// Not bin file - enhancer may work, if assembly doesn't contain |
204 | ························// persistent classes. |
205 | ························messages.WriteLine("Can't load referenced Assembly '" + dllPath +". The enhancer may not work correctly."); |
206 | ····················} |
207 | ····················else |
208 | ····················{ |
209 | ························throw new Exception("Can't load referenced Assembly '" + projectDescription.BinFile + ". " + ex.Message); |
210 | ····················} |
211 | ····················continue; |
212 | ················} |
213 | |
214 | ················string assName = assToLoad.Name; |
215 | ················if (this.assemblyFullNames.Contains(assName)) |
216 | ················{ |
217 | ····················messages.WriteLine("Assembly '" + assName + "' analyzed twice. Check your .ndoproj file."); |
218 | ····················continue; |
219 | ················} |
220 | ················this.assemblyFullNames.Add(assName, assToLoad.FullName); |
221 | |
222 | ················if (verboseMode) |
223 | ················{ |
224 | ····················messages.WriteLine("Checking DLL: " + dllPath); |
225 | ····················messages.WriteLine("BinFile: " + binFile); |
226 | ················} |
227 | |
228 | ················AssemblyNode assemblyNode = null; |
229 | ················CheckNDO(ass); |
230 | |
231 | ················try |
232 | ················{ |
233 | ····················assemblyNode = new AssemblyNode(ass, this.mappings); |
234 | ················} |
235 | ················catch (Exception ex) |
236 | ················{ |
237 | ····················if (verboseMode) |
238 | ························messages.ShowError("Error while reflecting types of assembly " + dllPath + ". " + ex); |
239 | ····················else |
240 | ························messages.ShowError("Error while reflecting types of assembly " + dllPath + ". " + ex.Message); |
241 | ················} |
242 | |
243 | ················if (ownAssembly) |
244 | ················{ |
245 | ····················ownClassList = assemblyNode.PersistentClasses; |
246 | ····················this.isEnhanced = assemblyNode.IsEnhanced; |
247 | ····················this.oidTypeName = assemblyNode.OidTypeName; |
248 | ····················this.ownAssemblyName = assName; |
249 | ····················Corlib.FxType = assemblyNode.TargetFramework == ".NETStandard,Version=v2.0" ? FxType.Standard2 : FxType.NetFx; |
250 | ····················if (this.verboseMode) |
251 | ························messages.WriteLine( $"FxType: {ownAssemblyName}: {Corlib.FxType}" ); |
252 | ················} |
253 | |
254 | ················ArrayList classList = assemblyNode.PersistentClasses; |
255 | ················foreach(ClassNode classNode in classList) |
256 | ················{ |
257 | ····················string clName = classNode.Name; |
258 | ····················if (!allPersistentClasses.Contains(clName)) |
259 | ························allPersistentClasses.Add(clName, classNode); |
260 | ····················else if (verboseMode) |
261 | ························messages.WriteLine("Multiple definition of Class " + clName + '.'); |
262 | ················} |
263 | |
264 | ················// Wir haben externe persistente Klassen gefunden. |
265 | ················// Mapping-Info einlesen. |
266 | ················if (!ownAssembly) |
267 | ····················mergeMappingFile(dllPath, classList); |
268 | ················if (!ownAssembly) |
269 | ····················mergeDataSet(dllPath, classList); |
270 | |
271 | ················if (ownAssembly) |
272 | ················{ |
273 | ····················this.hasPersistentClasses = (classList.Count > 0); |
274 | ················} |
275 | |
276 | ················// TODO: Check, how to handle value types |
277 | //················XmlNodeList vtnl = pcDoc.SelectNodes(@"/PersistentClasses/ValueType"); |
278 | //················ValueTypes.Instance.Merge(vtnl); |
279 | ············} |
280 | |
281 | ············if (projectDescription.IsWebProject || !options.EnableEnhancer) |
282 | ············{ |
283 | ················ownClassList = new ArrayList(); |
284 | ············} |
285 | ············else |
286 | ············{ |
287 | ················if (ownClassList == null) |
288 | ····················throw new Exception("A reference to the assembly " + binFile + " is needed. Check your parameter file."); |
289 | ············} |
290 | |
291 | ············checkClassMappings(ownClassList); |
292 | ············checkTypeList(); |
293 | ············checkOidColumnMappings(); // Incorporates the Attributes and NDOOidType. |
294 | ············checkAllRelationMappings(ownClassList); // Makes sure, that a mapping entry for each relation exists |
295 | ············determineOidTypes(); // needs the relation mappings, calls InitFields |
296 | ············checkRelationForeignKeyMappings(); // Calls r.InitFields, therefore requires, that InitFields for the Oid's was called |
297 | ············generateAllSchemas(); |
298 | ············removeRedundantOidColumnNames(); |
299 | ········} |
300 | |
301 | |
302 | ········private void removeRedundantOidColumnNames() |
303 | ········{ |
304 | ············foreach (Class cl in mappings.Classes) |
305 | ············{ |
306 | ················new OidColumnIterator(cl).Iterate(delegate(OidColumn oidColumn, bool isLastElement) |
307 | ················{ |
308 | ····················if (oidColumn.FieldName == string.Empty) |
309 | ························oidColumn.FieldName = null; |
310 | ····················if (oidColumn.RelationName == string.Empty) |
311 | ························oidColumn.RelationName = null; |
312 | ····················if (oidColumn.FieldName != null || oidColumn.RelationName != null) |
313 | ····················{ |
314 | ························oidColumn.Name = null;······// Let the field or relation define the name |
315 | ························oidColumn.NetType = null;·· // Let the field or relation determine the type |
316 | ····················} |
317 | ················}); |
318 | ············} |
319 | ········} |
320 | |
321 | ········private void checkOidColumnMappings() |
322 | ········{ |
323 | ············foreach (Class cl in mappings.Classes) |
324 | ············{ |
325 | |
326 | ················ClassNode classNode = allPersistentClasses[cl.FullName]; |
327 | ················if (classNode == null) |
328 | ················{ |
329 | ····················messages.WriteLine("Warning: can't find ClassNode for class " + cl.FullName); |
330 | ····················continue; |
331 | ················} |
332 | ················ClassOid oid = cl.Oid; |
333 | ················if (oid.OidColumns.Count == 0 && !classNode.ColumnAttributes.Any()) |
334 | ················{ |
335 | ····················OidColumn oidColumn = oid.NewOidColumn(); |
336 | ····················oidColumn.Name = "ID"; |
337 | ················} |
338 | |
339 | ················// Check, if the oid columns match the OidColumnAttributes, if any of them exist |
340 | ················// In case of NDOOidType the ClassNode constructor creates an OidColumnAttribute |
341 | |
342 | ················oid.RemapOidColumns(classNode.ColumnAttributes); |
343 | |
344 | ················bool noNameError = false; |
345 | |
346 | ················new OidColumnIterator(cl).Iterate(delegate(OidColumn oidColumn, bool isLastElement) |
347 | ················{ |
348 | ····················if (string.IsNullOrEmpty(oidColumn.Name) && string.IsNullOrEmpty(oidColumn.FieldName) && string.IsNullOrEmpty(oidColumn.RelationName)) |
349 | ····················{ |
350 | ························noNameError = true; |
351 | ························messages.WriteLine("Error: Oid column of class " + cl.FullName + " doesn't have a column name."); |
352 | ····················} |
353 | ················}); |
354 | ················if (noNameError) |
355 | ····················throw new Exception("If you define several OidColumns with the OidColumnAttribute, you have to assign a name for each column."); |
356 | ············} |
357 | ········} |
358 | |
359 | ········/// <summary> |
360 | ········/// Checks, if all foreign key mapping entries match the oid columns of the target types |
361 | ········/// </summary> |
362 | ········private void checkRelationForeignKeyMappings() |
363 | ········{ |
364 | ············// Now check, if all relations have correct foreign keys |
365 | ············foreach (Class cl in mappings.Classes) |
366 | ············{ |
367 | ················foreach (Relation r in cl.Relations) |
368 | ················{ |
369 | ····················/* |
370 | ···················· * 1. klären, ob ForeignKeyColumns oder ChildForeignKeyColumns relevant sind |
371 | ···················· *······- Multiplicity··Ist die schon bekannt? |
372 | ···················· *······- ChildForeignKeyColumnAttributes |
373 | ···················· *······- r.MappingTable··RelationMappings sollten schon bestimmt sein |
374 | ···················· * 2. Count vergleichen, bei MappingTable auch für eigenen Oid-Typ. Warnung bei != |
375 | ···················· * 3. Bei Bedarf remappen |
376 | ···················· * Präzedenz:·· 1. Attribute |
377 | ···················· *··············2. Mapping File |
378 | ···················· *··············3. Defaults |
379 | ···················· */ |
380 | ····················//Class relClass = allPersistentClasses[r.ReferencedTypeName].Class; |
381 | ····················//if (relClass.Oid.OidColumns != r. |
382 | ····················//r.RemapForeignKeyColumns(); |
383 | ················} |
384 | |
385 | ················foreach (IFieldInitializer fi in cl.Relations) |
386 | ····················fi.InitFields(); |
387 | |
388 | ············} |
389 | ········} |
390 | ················ |
391 | ········private IList checkRelationTargetAssemblies() |
392 | ········{ |
393 | ············ArrayList foreignAssemblies = new ArrayList(); |
394 | ············foreach(Class cl in this.mappings.Classes) |
395 | ············{ |
396 | ················foreach(Relation r in cl.Relations) |
397 | ················{ |
398 | ····················ClassNode classNode = this.allPersistentClasses[r.ReferencedTypeName]; |
399 | ····················if (classNode == null) |
400 | ························throw new InternalException(242, "Enhancer.checkRelationTargetAssemblies"); |
401 | ····················if (classNode.AssemblyName != this.ownAssemblyName) |
402 | ····················{ |
403 | ························if (!foreignAssemblies.Contains(classNode.AssemblyName)) |
404 | ····························foreignAssemblies.Add(classNode.AssemblyName); |
405 | ····················} |
406 | ················} |
407 | ············} |
408 | ············return foreignAssemblies; |
409 | ········} |
410 | ········ |
411 | #if nix·· // should now be done in InitFields |
412 | ········private void checkAllMultiplicities() |
413 | ········{ |
414 | ············foreach(Class cl in mappings.Classes) |
415 | ············{ |
416 | ················foreach(Relation r in cl.Relations) |
417 | ················{ |
418 | ····················// Setting the class with reflection |
419 | ····················RelationNode definingNode = getDefiningNodeForRelation(r); |
420 | ····················if (definingNode == null) // Relation might be deleted |
421 | ························continue; |
422 | ····················Class definingClass = allPersistentClasses[definingNode.Parent.Name].Class; |
423 | ····················SetDefiningClass(r, definingClass); |
424 | |
425 | ····················r.Multiplicity = definingNode.IsElement |
426 | ························? RelationMultiplicity.Element |
427 | ························: RelationMultiplicity.List; |
428 | ················} |
429 | ············} |
430 | ········} |
431 | |
432 | ········private RelationNode getDefiningNodeForRelation(Relation r) |
433 | ········{ |
434 | ············ClassNode classNode = allPersistentClasses[r.Parent.FullName]; |
435 | ············if (classNode == null) |
436 | ················throw new InternalException(239, "Enhancer: getDefiningClassForRelation; can't find ClassNode for " + r.Parent.FullName); |
437 | |
438 | ············while (classNode != null) |
439 | ············{ |
440 | ················foreach(RelationNode rn in classNode.Relations) |
441 | ····················if (rn.Name == r.FieldName) |
442 | ························return rn; |
443 | ················classNode = this.allPersistentClasses[classNode.BaseName]; |
444 | ············} |
445 | ············//throw new Exception("Can't find defining ClassNode for relation " + r.Parent.FullName + "." + r.FieldName + ". Check your mapping file for unnecessary Relation entries."); |
446 | ············return null; // Relation might be deleted |
447 | ········} |
448 | |
449 | #endif |
450 | |
451 | #if PRO |
452 | |
453 | ········private void checkTypeList() |
454 | ········{ |
455 | ············string typeFile = Path.Combine(Path.GetDirectoryName(binFile), "NDOTypes.Xml"); |
456 | ············TypeManager tm = new TypeManager(typeFile, this.mappings); |
457 | ············tm.CheckTypeList(allPersistentClasses); |
458 | ········} |
459 | #endif |
460 | |
461 | ········void generateAllSchemas() |
462 | ········{ |
463 | ············dsSchema.Remap(mappings); |
464 | #if nix |
465 | ············foreach(DictionaryEntry de in this.allPersistentClasses) |
466 | ············{ |
467 | ················ClassNode classNode = (ClassNode) de.Value; |
468 | ················if (classNode.IsAbstractOrInterface) |
469 | ····················continue; |
470 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
471 | ····················continue; |
472 | ················string pureName = classNode.Name; |
473 | ················Class classMapping = classNode.Class; |
474 | ················new SchemaGenerator(classMapping, mappings, dsSchema, messages, allSortedFields, allPersistentClasses, verboseMode).GenerateTables(); |
475 | ············} |
476 | ············foreach(DictionaryEntry de in this.allPersistentClasses) |
477 | ············{ |
478 | ················ClassNode classNode = (ClassNode) de.Value; |
479 | ················if (classNode.IsAbstractOrInterface) |
480 | ····················continue; |
481 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
482 | ····················continue; |
483 | ················string pureName = classNode.Name; |
484 | ················Class classMapping = classNode.Class; |
485 | ················new SchemaGenerator(classMapping, mappings, dsSchema, messages, allSortedFields, allPersistentClasses, verboseMode).GenerateRelations(); |
486 | ············} |
487 | #endif |
488 | ········} |
489 | |
490 | |
491 | |
492 | ········public void |
493 | ········mergeDataSet(string absDllPath, ArrayList classList) |
494 | ········{············ |
495 | ············string dsFile = Path.Combine(Path.GetDirectoryName(absDllPath), Path.GetFileNameWithoutExtension(absDllPath) + ".ndo.xsd"); |
496 | ············if (!File.Exists(dsFile)) |
497 | ················return; |
498 | |
499 | ············NDODataSet dsToMerge = new NDODataSet(dsFile); |
500 | ············foreach(DataTable dt in dsToMerge.Tables) |
501 | ············{ |
502 | ················if (null == dsSchema.Tables[dt.TableName]) |
503 | ················{ |
504 | ····················DataTable newdt = dt.Clone(); |
505 | ····················dsSchema.Tables.Add(newdt); |
506 | ················} |
507 | ············} |
508 | ············foreach(DataRelation dr in dsToMerge.Relations) |
509 | ············{ |
510 | ················if (null == dsSchema.Relations[dr.RelationName]) |
511 | ················{ |
512 | ····················DataRelation newdr = null; |
513 | ····················try |
514 | ····················{ |
515 | ························dsSchema.Relations.Add( newdr = new DataRelation( dr.RelationName, dsSchema.Tables[dr.ParentTable.TableName].Columns[dr.ParentColumns[0].ColumnName], dsSchema.Tables[dr.ChildTable.TableName].Columns[dr.ChildColumns[0].ColumnName], true ) ); |
516 | ····················} |
517 | ····················catch(Exception ex) |
518 | ····················{ |
519 | ························string relName = "null"; |
520 | ························if (dr != null && dr.RelationName != null) |
521 | ····························relName = dr.RelationName; |
522 | |
523 | ························throw new Exception("Error while merging relation '" + relName + "' into the new dataset: " + ex.Message); |
524 | ····················} |
525 | ····················newdr.ChildKeyConstraint.DeleteRule = dr.ChildKeyConstraint.DeleteRule; |
526 | ····················newdr.ChildKeyConstraint.UpdateRule = dr.ChildKeyConstraint.UpdateRule; |
527 | ················} |
528 | ············} |
529 | ········} |
530 | |
531 | #if nix |
532 | ········private void getOidType(FieldNode fieldNode, Class cls) |
533 | ········{ |
534 | ············Type t = fieldNode.OidType; |
535 | ············if (t == null) |
536 | ············{ |
537 | ················messages.WriteLine(String.Format("Invalid Oid type {0} in class {1} - using int instead.", fieldNode.DataType, cls.FullName)); |
538 | ················t = typeof(int); |
539 | ············} |
540 | ············cls.Oid.FieldType = t; |
541 | ········} |
542 | #endif |
543 | ········private void |
544 | ········determineOidTypes() |
545 | ········{ |
546 | ············foreach (Class cl in mappings.Classes) |
547 | ············{ |
548 | ················ClassNode classNode = (ClassNode)allPersistentClasses[cl.FullName]; |
549 | ················if (classNode == null) |
550 | ················{ |
551 | ····················mappings.RemoveClass( cl ); |
552 | ····················continue; |
553 | ················} |
554 | ················cl.IsAbstract = classNode.IsAbstract;··// usually this is set in Class.InitFields, which isn't called by the Enhancer. |
555 | ················cl.SystemType = classNode.ClassType; |
556 | ············} |
557 | ············foreach(Class cl in mappings.Classes) |
558 | ············{ |
559 | ················string className = cl.FullName; |
560 | |
561 | ················// Even abstract types should have an oid type, |
562 | ················// because they can be targets of relations - thus |
563 | ················// we need a foreign key column type. |
564 | |
565 | ················ClassOid oid = cl.Oid; |
566 | ················if (oid == null) |
567 | ····················throw new Exception("MergeOidTypes: Can't find Oid Mapping for class " + className); |
568 | |
569 | #if DEBUG |
570 | ················if (cl.FullName.IndexOf("OrderDetail") > -1) |
571 | ····················Console.WriteLine(); |
572 | #endif |
573 | |
574 | ················((IFieldInitializer)oid).InitFields(); |
575 | ············} |
576 | ········} |
577 | |
578 | |
579 | ········private void checkMappingForField(string prefix, Patcher.ILField field, ArrayList sortedFields, Class classMapping, bool isOnlyChild, FieldNode fieldNode) |
580 | ········{ |
581 | ············bool isOidField = fieldNode.IsOid; |
582 | ············if (field.CleanName.StartsWith("_ndo")) |
583 | ············{ |
584 | ················if (this.verboseMode) |
585 | ····················messages.WriteLine("Warning: **** found _ndo field: " + field.CleanName); |
586 | ················return; |
587 | ············} |
588 | ············string fname = prefix + field.CleanName; |
589 | ············if (field.HasNestedFields) |
590 | ············{ |
591 | ················bool oneChildOnly = field.Fields.Count == 1; |
592 | ················foreach(Patcher.ILField newf in field.Fields) |
593 | ················{ |
594 | ····················checkMappingForField(field.CleanName + ".", newf, sortedFields, classMapping, oneChildOnly, fieldNode); |
595 | ················} |
596 | ················return; |
597 | ············} |
598 | ············DictionaryEntry deToDelete = new DictionaryEntry(string.Empty, string.Empty); |
599 | ············if (field.IsInherited) |
600 | ············{ |
601 | ················foreach(DictionaryEntry de in sortedFields) |
602 | ····················if (de.Key.Equals(fname)) |
603 | ························deToDelete = de; |
604 | ············} |
605 | ············if (((string)deToDelete.Key) != string.Empty) |
606 | ················deToDelete.Value = field; |
607 | ············else |
608 | ················sortedFields.Add(new DictionaryEntry(fname, field)); |
609 | |
610 | ············if (classMapping != null) |
611 | ············{ |
612 | ················Field f = classMapping.FindField(fname); |
613 | ················if (null == f) |
614 | ················{ |
615 | ····················f = classMapping.AddStandardField(fname, isOidField); |
616 | ····················if (isOnlyChild) |
617 | ························f.Column.Name = classMapping.ColumnNameFromFieldName(field.Parent.CleanName, false); |
618 | ····················messages.WriteLine("Generating field mapping: " + classMapping.FullName + "." + fname + " -> " + f.Column.Name); |
619 | ····················if (classMapping.IsAbstract) |
620 | ························f.Column.Name = "Unused"; |
621 | ················} |
622 | ················if (fieldNode.ColumnAttribute != null) |
623 | ················{ |
624 | ····················fieldNode.ColumnAttribute.SetColumnValues( f.Column ); |
625 | ················} |
626 | ············} |
627 | ········} |
628 | |
629 | ········/// <summary> |
630 | ········/// Helps sorting the fields |
631 | ········/// </summary> |
632 | ········private class FieldSorter : IComparer |
633 | ········{ |
634 | ············public int Compare(object x, object y) |
635 | ············{ |
636 | ················if (!(x is DictionaryEntry) || !(y is DictionaryEntry)) |
637 | ····················throw new Exception("Interner Fehler: FieldSorter.Compare: DictionaryEntry erwartet; x= " + x.GetType().FullName + " y = " + y.GetType().FullName); |
638 | ················return String.CompareOrdinal((string)((DictionaryEntry) x).Key, (string)((DictionaryEntry) y).Key); |
639 | ············} |
640 | ········} |
641 | |
642 | |
643 | ········private void IterateFieldNodeList(IList fieldList, bool isEmbeddedObject, |
644 | ············List<FieldNode> oidFields, Class classMapping, ArrayList sortedFields, |
645 | ············bool isInherited) |
646 | ········{ |
647 | ············string tn; |
648 | ············foreach(FieldNode fieldNode in fieldList) |
649 | ············{ |
650 | ················// Beim Anlegen eines Fields werden auch gleich die SubFields angelegt, |
651 | ················// wenn das Field ein Value Type ist |
652 | ················string thename = fieldNode.Name; |
653 | ················tn = fieldNode.DataType; |
654 | ················//Debug.WriteLine(tn); |
655 | ················string pattern = @"(class\s|valuetype\s|)(\[[^\]]+\]|)"; |
656 | ················Regex regex = new Regex(pattern); |
657 | ················Match match = regex.Match(tn); |
658 | ················if (match.Groups[2].Value == "[" + ownAssemblyName + "]") |
659 | ····················tn = tn.Replace(match.Groups[2].Value, ""); |
660 | |
661 | ················if (!isEmbeddedObject && fieldNode.IsOid) |
662 | ····················oidFields.Add(fieldNode); |
663 | ················IList subFieldList = null; |
664 | ················if (isEmbeddedObject) |
665 | ················{ |
666 | ····················subFieldList = fieldNode.Fields; |
667 | ················} |
668 | |
669 | ················bool isEnum = (fieldNode.IsEnum); |
670 | ················Patcher.ILField field = new Patcher.ILField(fieldNode.FieldType, tn, |
671 | ····················fieldNode.Name, this.ownAssemblyName, subFieldList, isEnum); |
672 | ················field.IsInherited = isInherited; |
673 | ················System.Diagnostics.Debug.Assert (field.Valid, "field.Valid is false"); |
674 | ················if (classMapping != null) |
675 | ····················checkMappingForField("", field, sortedFields, classMapping, false, fieldNode); |
676 | ············} |
677 | ········} |
678 | ············ |
679 | |
680 | ········private void |
681 | ········checkFieldMappings(ClassNode classNode, Class classMapping) |
682 | ········{ |
683 | ············ArrayList sortedFields = new ArrayList(); |
684 | ············string className = classNode.Name; |
685 | ············allSortedFields.Add(className, sortedFields); |
686 | |
687 | ············List<FieldNode> oidFields = new List<FieldNode>(); |
688 | |
689 | ············// All own fields |
690 | ············IList fieldList = classNode.Fields; |
691 | ············IterateFieldNodeList(fieldList, false, oidFields, classMapping, sortedFields, false); |
692 | |
693 | ············// All embedded objects |
694 | ············IList embeddedObjectsList = classNode.EmbeddedTypes; |
695 | ············IterateFieldNodeList(embeddedObjectsList, true, oidFields, classMapping, sortedFields, false); |
696 | |
697 | ············FieldSorter fieldSorter = new FieldSorter(); |
698 | ············sortedFields.Sort(fieldSorter); |
699 | |
700 | ············// Alle ererbten Felder |
701 | ············ClassNode derivedclassNode = this.allPersistentClasses[classNode.BaseName]; |
702 | ············ |
703 | ············while (null != derivedclassNode) |
704 | ············{ |
705 | ················if (derivedclassNode.IsPersistent) |
706 | ················{ |
707 | ····················int startind = sortedFields.Count; |
708 | |
709 | ····················IList nl = derivedclassNode.Fields; |
710 | ····················IterateFieldNodeList(nl, false, oidFields, classMapping, sortedFields, true); |
711 | ················ |
712 | ····················IList enl = derivedclassNode.EmbeddedTypes; |
713 | ····················IterateFieldNodeList(enl, true, oidFields, classMapping, sortedFields, true); |
714 | |
715 | ····················int len = sortedFields.Count - startind; |
716 | ····················sortedFields.Sort(startind, len, fieldSorter); |
717 | ················} |
718 | ················derivedclassNode = this.allPersistentClasses[derivedclassNode.BaseName]; |
719 | ············} |
720 | |
721 | ············// Ab hier nur noch Zeug für die Mapping-Datei |
722 | ············if (classMapping == null) |
723 | ················return; |
724 | |
725 | |
726 | ············if (oidFields.Count > 0) |
727 | ············{ |
728 | ················foreach (FieldNode oidField in oidFields) |
729 | ················{ |
730 | ····················OidColumn oidColumn = null; |
731 | ····················new OidColumnIterator(classMapping).Iterate(delegate(OidColumn oidCol, bool isLastElement) |
732 | ····················{ |
733 | ························if (oidCol.FieldName == oidField.Name) |
734 | ····························oidColumn = oidCol; |
735 | ····················}); |
736 | ····················if (oidColumn == null) |
737 | ····················{ |
738 | ························oidColumn = classMapping.Oid.NewOidColumn(); |
739 | ························oidColumn.FieldName = oidField.Name; |
740 | ························oidColumn.Name = classMapping.FindField(oidField.Name).Column.Name; |
741 | ····················} |
742 | ················} |
743 | ············} |
744 | |
745 | ············foreach(DictionaryEntry de in sortedFields) |
746 | ················sortedFieldsFile.WriteLine((string)de.Key); |
747 | ············sortedFieldsFile.WriteLine(); |
748 | |
749 | |
750 | ············// Und nun die überflüssigen entfernen |
751 | ············List<Field> fieldsToRemove = new List<Field>(); |
752 | ············foreach(Field f in classMapping.Fields) |
753 | ············{ |
754 | ················bool isExistent = false; |
755 | ················foreach(DictionaryEntry e in sortedFields) |
756 | ················{ |
757 | ····················if ((string)e.Key == f.Name) |
758 | ····················{ |
759 | ························isExistent = true; |
760 | ························break; |
761 | ····················} |
762 | ················} |
763 | ················if (!isExistent) |
764 | ····················fieldsToRemove.Add(f); |
765 | ············} |
766 | ············foreach(Field field in fieldsToRemove) |
767 | ················classMapping.RemoveField(field); |
768 | |
769 | ············List<Field> sortedFieldMappings = classMapping.Fields.ToList(); |
770 | ············sortedFieldMappings.Sort( ( f1, f2 ) => string.CompareOrdinal( ((Field)f1).Name, ((Field)f2).Name ) ); |
771 | ············for (int i = 0; i < sortedFieldMappings.Count; i++) |
772 | ················((Field)sortedFieldMappings[i]).Ordinal = i; |
773 | ········} |
774 | |
775 | |
776 | ········private void SetDefiningClass(Relation r, Class parent) |
777 | ········{ |
778 | ············Type t = typeof(Relation); |
779 | ············FieldInfo fi = t.GetField("definingClass", BindingFlags.NonPublic | BindingFlags.Instance); |
780 | ············fi.SetValue(r, parent); |
781 | ········} |
782 | |
783 | ········public void |
784 | ········checkInheritedRelationMappings(ClassNode classNode, Class classMapping) |
785 | ········{ |
786 | ············string className = classNode.Name; |
787 | |
788 | ············ReferenceArrayList references = (ReferenceArrayList) this.allReferences[className]; |
789 | ············// Alle ererbten Relationen |
790 | ············ClassNode baseClassNode = this.allPersistentClasses[classNode.BaseName]; |
791 | ············ |
792 | ············while (null != baseClassNode) |
793 | ············{ |
794 | ················if (baseClassNode.IsPersistent) |
795 | ················{ |
796 | ····················Class baseClassMapping = baseClassNode.Class; |
797 | ····················ArrayList temp = new ArrayList(); |
798 | ····················IList nl = baseClassNode.Relations; |
799 | ····················foreach (RelationNode relNode in nl) |
800 | ····················{ |
801 | ························// Relation nur aus der Klasse nehmen, die das Feld deklariert |
802 | ························if (relNode.DeclaringType != null) |
803 | ····························continue; |
804 | ························//····················string tn = relNode.Attributes["Type"].Value; |
805 | ························RelationInfo ri = relNode.RelationInfo; |
806 | ························string rname = relNode.Name; |
807 | ························ |
808 | ························// Die Relation sollte wirklich am unteren Ende der |
809 | ························// Klassenhierarchie erzeugt werden. |
810 | ························//····················if(references.Contains(rname)) |
811 | ························//····················Debug.Write("NDO635"); |
812 | ························Debug.Assert(!references.Contains(rname)); |
813 | ········································ |
814 | |
815 | ························// relation wird als ererbte Reference in die Liste eingetragen. |
816 | ························bool is1To1 = relNode.IsElement; |
817 | ························string relTypeName = relNode.RelatedType; |
818 | ························string relName = relNode.RelationName; |
819 | ························string ilType = relNode.DataType; |
820 | ························Type containerType = relNode.FieldType; |
821 | |
822 | ························ClassNode relClassNode = allPersistentClasses[relTypeName]; |
823 | ························if (relClassNode.AssemblyName != this.ownAssemblyName && !relTypeName.StartsWith("[")) |
824 | ····························relTypeName = "[" + relClassNode.AssemblyName + "]" + relTypeName; |
825 | ························//TODO: warnen wenn Oid-Typen nicht übereinstimmen |
826 | ························references.Add(new Patcher.ILReference(containerType, relTypeName, ilType, rname, this.ownAssemblyName, ri, relName, true, is1To1, "class " + className)); |
827 | |
828 | ························if (classMapping != null) |
829 | ························{ |
830 | ····························// Ist diese Relation schon definiert? Wenn ja, wird sie nicht geändert |
831 | ····························Relation r = classMapping.FindRelation(rname); |
832 | ····························if (null == r) |
833 | ····························{ |
834 | ································messages.WriteLine(String.Format("Ererbte Relation {0}.{1} wird kopiert", classNode.Name, rname)); |
835 | ································if (null == baseClassMapping) |
836 | ····································throw new Exception(String.Format("Kann die Mapping-Information für die Basisklasse {0} nicht finden", baseClassNode.Name)); |
837 | ································r = baseClassMapping.FindRelation(rname); |
838 | ································if (r == null) |
839 | ····································throw new Exception(String.Format("Schwerwiegender interner Fehler: Ererbte Relation {0} in Basisklasse {1} nicht gefunden.", rname, baseClassMapping.FullName));································ |
840 | ································classMapping.AddRelation(r); |
841 | ····························} |
842 | ····························else |
843 | ····························{ |
844 | ································Relation orgRel = baseClassMapping.FindRelation( rname ); |
845 | ································if (r.AccessorName == null && r.AccessorName != orgRel.AccessorName) |
846 | ····································r.AccessorName = orgRel.AccessorName; |
847 | ····························} |
848 | ····························if (is1To1) |
849 | ································r.Multiplicity = RelationMultiplicity.Element; |
850 | ····························else |
851 | ································r.Multiplicity = RelationMultiplicity.List; |
852 | ························} |
853 | ····················} |
854 | ················} |
855 | ················baseClassNode = this.allPersistentClasses[baseClassNode.BaseName]; |
856 | ············} |
857 | ········} |
858 | |
859 | ········public void |
860 | ········checkRelationMappings(ClassNode classNode, Class classMapping) |
861 | ········{ |
862 | ············IList references = new ReferenceArrayList(); |
863 | ············string className = (classNode.Name); |
864 | ············allReferences.Add(className, references); |
865 | ············IList refList = classNode.Relations; |
866 | ············foreach (RelationNode relationNode in refList) |
867 | ············{ |
868 | ················// Übernehme die Relation nur aus der deklarierenden Klasse, |
869 | ················// damit gleich die richtigen Mappings eingetragen werden. |
870 | ················if (relationNode.DeclaringType != null) |
871 | ····················continue; |
872 | ················string fieldName = relationNode.Name; |
873 | ················string relTypeName = relationNode.RelatedType; |
874 | ················bool is1To1 = relationNode.IsElement; |
875 | ················string relName = relationNode.RelationName; |
876 | ················RelationInfo ri = relationNode.RelationInfo; |
877 | ················string ilType = relationNode.DataType; |
878 | ················Type containerType = relationNode.FieldType; |
879 | |
880 | ················if (!classNode.IsInterface) |
881 | ················{ |
882 | ····················if (classMapping == null) |
883 | ························continue; |
884 | ····················Relation r = classMapping.FindRelation(fieldName); |
885 | ····················ClassNode relClassNode = allPersistentClasses[relTypeName]; |
886 | ····················if (null == r) |
887 | ····················{ |
888 | ························//TODO: ForeignKeyColumnAttributes... |
889 | ························string relTypeFullName = relTypeName.Substring(relTypeName.IndexOf("]") + 1);························ |
890 | ························if (relClassNode == null) |
891 | ····························throw new Exception(String.Format("Class '{1}' has a relation to a non persistent type '{0}'.", relTypeFullName, classNode.Name)); |
892 | ························messages.WriteLine("Creating standard relation " + classNode.Name + "." + fieldName); |
893 | ························r = classMapping.AddStandardRelation(fieldName, relTypeFullName, is1To1, relName, classNode.IsPoly, relClassNode.IsPoly || relClassNode.IsAbstract, relationNode.MappingTableAttribute); |
894 | ····················} |
895 | ····················else |
896 | ····················{ |
897 | ························r.RemapMappingTable( classNode.IsPoly, relClassNode.IsPoly || relClassNode.IsAbstract, relationNode.MappingTableAttribute ); |
898 | ························r.RemapForeignKeyColumns( relationNode.ForeignKeyColumnAttributes, relationNode.ChildForeignKeyColumnAttributes );··// currently nothing happens there. |
899 | ····················} |
900 | ····················SetDefiningClass(r, classMapping); |
901 | ····················if (is1To1) |
902 | ························r.Multiplicity = RelationMultiplicity.Element; |
903 | ····················else |
904 | ························r.Multiplicity = RelationMultiplicity.List; |
905 | ················} |
906 | ················references.Add(new Patcher.ILReference(containerType, relTypeName, ilType, fieldName, this.ownAssemblyName, ri, relName, false, is1To1, null)); |
907 | ············} |
908 | ········} |
909 | |
910 | |
911 | ········private void |
912 | ········checkClassMappings(ArrayList classList) |
913 | ········{ |
914 | ············if (options.DatabaseOwner != string.Empty) |
915 | ················mappings.StandardDbOwner = options.DatabaseOwner; |
916 | ············sortedFieldsFile = new StreamWriter(Path.ChangeExtension(binFile, ".fields.txt")); |
917 | ············foreach(ClassNode classNode in classList) |
918 | ············{ |
919 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
920 | ····················continue; |
921 | ················string assName = classNode.AssemblyName; |
922 | ················if (verboseMode) |
923 | ················{ |
924 | ····················if (assName != this.ownAssemblyName) |
925 | ························messages.WriteLine("Warning: Inconsistency: Class from foreign assembly: " + classNode.Name); |
926 | ················} |
927 | ················Class classMapping = null; |
928 | ················if (!classNode.IsInterface) |
929 | ················{ |
930 | ····················string className = classNode.Name; |
931 | ····················sortedFieldsFile.WriteLine(className + ":"); |
932 | ····················classMapping = mappings.FindClass(className); |
933 | ····················if (classMapping == null) |
934 | ····················{ |
935 | #if !STD |
936 | ························try |
937 | ························{ |
938 | #endif |
939 | ····························messages.WriteLine("Generating class mapping for class '" + className + "'"); |
940 | |
941 | ····························if (classNode.IsAbstract) |
942 | ································classMapping = mappings.AddAbstractClass(className, assName, classNode.ColumnAttributes); |
943 | ····························else |
944 | ································classMapping = mappings.AddStandardClass(className, assName, classNode.ColumnAttributes); |
945 | ························ |
946 | #if !STD |
947 | ························} |
948 | ························catch (ArgumentOutOfRangeException ex) |
949 | ························{ |
950 | ····························throw new Exception(Decryptor.Decrypt(NDOErrors.TooMuchClasses)); |
951 | ························} |
952 | #endif |
953 | ···························· |
954 | ····················} |
955 | ····················if (options.UseTimeStamps && (classMapping.TimeStampColumn == null || classMapping.TimeStampColumn == string.Empty)) |
956 | ························classMapping.TimeStampColumn = "NDOTimeStamp"; |
957 | ····················if (classNode.ClassType.IsGenericType && classMapping.TypeNameColumn == null) |
958 | ························classMapping.AddTypeNameColumn(); |
959 | ················} |
960 | ················checkFieldMappings(classNode, classMapping); |
961 | ············} |
962 | ············sortedFieldsFile.Close(); |
963 | |
964 | ············// Lösche ungebrauchte Class Mappings |
965 | ············ArrayList classesToDelete = new ArrayList(); |
966 | ············foreach(Class c in mappings.Classes) |
967 | ············{ |
968 | ················if (!tabuClasses.Contains(c.FullName) |
969 | ················&& allPersistentClasses[c.FullName] == null) |
970 | ························classesToDelete.Add(c); |
971 | ············} |
972 | ············foreach (Class c in classesToDelete) |
973 | ············{ |
974 | ················messages.WriteLine(String.Format("Deleting unused class mapping {0}", c.FullName)); |
975 | ················mappings.RemoveClass(c); |
976 | ············} |
977 | ········} |
978 | |
979 | ········private void checkAllRelationMappings(ArrayList classList) |
980 | ········{ |
981 | ············foreach(ClassNode classNode in classList) |
982 | ············{ |
983 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
984 | ····················continue; |
985 | ················Class classMapping = classNode.Class; |
986 | ················checkRelationMappings(classNode, classMapping); |
987 | ············} |
988 | |
989 | ············foreach(ClassNode classNode in classList) |
990 | ············{ |
991 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
992 | ····················continue; |
993 | ················Class classMapping = classNode.Class; |
994 | ················checkInheritedRelationMappings(classNode, classMapping); |
995 | ············} |
996 | |
997 | ············foreach(ClassNode classNode in classList) |
998 | ············{ |
999 | ················if (classNode.IsInterface) |
1000 | ····················continue; |
1001 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
1002 | ····················continue; |
1003 | ················Class classMapping = classNode.Class; |
1004 | ················if (classMapping == null) |
1005 | ····················continue; |
1006 | ················deleteUnusedRelationMappings(classMapping); |
1007 | ················checkDoubleComposites(classMapping); |
1008 | ············} |
1009 | ········} |
1010 | |
1011 | |
1012 | ········private void deleteUnusedRelationMappings(Class classMapping) |
1013 | ········{ |
1014 | ············ReferenceArrayList references = (ReferenceArrayList) this.allReferences[classMapping.FullName]; |
1015 | ············ArrayList relationsToDelete = new ArrayList(); |
1016 | ············foreach (Relation r in classMapping.Relations) |
1017 | ············{ |
1018 | ················if (!references.Contains(r.FieldName)) |
1019 | ····················relationsToDelete.Add(r); |
1020 | ············} |
1021 | ············foreach (Relation r in relationsToDelete) |
1022 | ············{ |
1023 | ················messages.WriteLine(String.Format("Delete unused Relation Mapping {0}", classMapping.FullName + "." + r.FieldName)); |
1024 | ················classMapping.RemoveRelation(r); |
1025 | ············} |
1026 | ········} |
1027 | |
1028 | ········private void checkDoubleComposites(Class classMapping) |
1029 | ········{ |
1030 | ············ReferenceArrayList references = (ReferenceArrayList) this.allReferences[classMapping.FullName]; |
1031 | ············foreach (Relation r in classMapping.Relations) |
1032 | ············{ |
1033 | ················Patcher.ILReference reference = references.FindReference(r.FieldName); |
1034 | ················if (reference != null) |
1035 | ················{ |
1036 | ····················Relation r2 = r.ForeignRelation; |
1037 | ····················if (r2 != null) |
1038 | ····················{ |
1039 | ························ReferenceArrayList references2 = (ReferenceArrayList) this.allReferences[r.ReferencedTypeName]; |
1040 | ························if(references2 == null)··// Type is not from our assembly |
1041 | ····························continue; |
1042 | ························Patcher.ILReference reference2 = references2.FindReference(r2.FieldName); |
1043 | ························if (reference2 != null) |
1044 | ························{ |
1045 | ····························if (reference.ReferenceInfo == RelationInfo.Composite |
1046 | ································&& reference2.ReferenceInfo == RelationInfo.Composite) |
1047 | ································throw new Exception(String.Format("Error: Bidirectional relation between class {0} and class {1} is a composite in both directions. Please remove the composite flag at one of the two classes.", classMapping.FullName, r.ReferencedTypeName)); |
1048 | ························} |
1049 | ····················} |
1050 | ················} |
1051 | ············} |
1052 | ········} |
1053 | |
1054 | |
1055 | ········public void |
1056 | ········mergeMappingFile(string absDllPath, ArrayList classList) |
1057 | ········{ |
1058 | ············var dir = Path.GetDirectoryName(absDllPath); |
1059 | ············var mapFileName = Path.Combine(dir, Path.GetFileNameWithoutExtension(absDllPath) + ".ndo.mapping"); |
1060 | ············if (!File.Exists( mapFileName )) |
1061 | ················mapFileName = Path.Combine(dir, "NDOMapping.xml"); |
1062 | |
1063 | ············if (classList.Count > 0 && !File.Exists(mapFileName)) |
1064 | ············{ |
1065 | ················messages.WriteLine("Mapping file for assembly " + absDllPath + " not found."); |
1066 | ················return; |
1067 | ············} |
1068 | |
1069 | ············NDOMapping mergeMapping; |
1070 | |
1071 | ············try |
1072 | ············{ |
1073 | ················mergeMapping = new NDOMapping(mapFileName); |
1074 | ············} |
1075 | ············catch (Exception ex) |
1076 | ············{ |
1077 | ················throw new Exception("Can't read mapping file " + mapFileName + ".\n"+ex.Message); |
1078 | ············} |
1079 | ············foreach(Class classMapping in mergeMapping.Classes) |
1080 | ················tabuClasses.Add(classMapping.FullName); |
1081 | |
1082 | ············mappings.MergeMapping(mergeMapping); |
1083 | |
1084 | ············foreach(ClassNode classNode in classList) |
1085 | ············{ |
1086 | ················Class cls; |
1087 | ················string className = classNode.Name; |
1088 | ················if (null == (cls = mappings.FindClass(className))) |
1089 | ················{ |
1090 | ····················messages.WriteLine("Mapping information for class " + className + " in file " + mapFileName + " not found."); |
1091 | ····················messages.WriteInsertedLine("Try to recompile the assembly " + absDllPath + "."); |
1092 | ················} |
1093 | ············} |
1094 | ········} |
1095 | |
1096 | ········private string CombinePath(string path, string file) |
1097 | ········{ |
1098 | ············string p = path; |
1099 | ············if (p.EndsWith("\\")) |
1100 | ················p = p.Substring(0, p.Length - 1); |
1101 | ············while (file.StartsWith(@"..\")) |
1102 | ············{ |
1103 | ················p = Path.GetDirectoryName(p); |
1104 | ················file = file.Substring(3); |
1105 | ············} |
1106 | ············return p + "\\" + file; |
1107 | ········} |
1108 | |
1109 | ········public void |
1110 | ············doIt() |
1111 | ········{ |
1112 | |
1113 | #if BETA || TRIAL |
1114 | ············expired = !NDOKey.CheckDate(new LicenceKey().TheKey, DateTime.Now); |
1115 | #endif |
1116 | ············bool sourcesUpToDate = !options.EnableEnhancer; |
1117 | #if BETA || TRIAL |
1118 | ············if (expired) |
1119 | ················throw new Exception("NDO Licence expired"); |
1120 | #endif |
1121 | #if DEBUG |
1122 | ············this.verboseMode = true; |
1123 | #else |
1124 | ············this.verboseMode = options.VerboseMode; |
1125 | #endif |
1126 | ············DateTime objTime = DateTime.MinValue; |
1127 | |
1128 | ············if (options.EnableEnhancer) |
1129 | ············{ |
1130 | ················DateTime enhTime; |
1131 | ················DateTime ilEnhTime; |
1132 | |
1133 | ················if (!File.Exists(objFile)) |
1134 | ················{ |
1135 | ····················messages.WriteLine("Enhancer: Kann Datei " + objFile + " nicht finden"); |
1136 | ····················return; |
1137 | ················} |
1138 | |
1139 | ················objTime = File.GetLastWriteTime(objFile); |
1140 | |
1141 | ················if (File.Exists(ilEnhFile) && File.Exists(enhFile)) |
1142 | ················{ |
1143 | ····················enhTime = File.GetLastWriteTime(enhFile); |
1144 | ····················ilEnhTime = File.GetLastWriteTime(ilEnhFile); |
1145 | |
1146 | ····················// objFile·· = obj\debug\xxx.dll |
1147 | ····················// ilEnhFile = obj\ndotemp\xxx.il |
1148 | ····················// enhFile·· = obj\ndotemp\xxx.dll |
1149 | ····················// binFile·· = bin\debug\xxx.dll |
1150 | ····················if (objTime < ilEnhTime && ilEnhTime <= enhTime) |
1151 | ····················{ |
1152 | ························// Sicherstellen, dass das Binary existiert |
1153 | ························File.Copy(enhFile, binFile, true); |
1154 | ························if (debug) |
1155 | ····························File.Copy(enhPdbFile, binPdbFile, true); |
1156 | |
1157 | ························sourcesUpToDate = true; |
1158 | ····················} |
1159 | ················} |
1160 | ············} |
1161 | ············// Mapping-Datei im Bin-Verzeichnis muss jünger oder gleich alt sein wie Mapping-Source-Datei |
1162 | ············if (sourcesUpToDate) |
1163 | ············{ |
1164 | ················if (File.Exists(mappingFile) && File.Exists(mappingDestFile)) |
1165 | ················{ |
1166 | ····················DateTime mapSourceTime = File.GetLastWriteTime(mappingFile); |
1167 | ····················DateTime mapDestTime = File.GetLastWriteTime(mappingDestFile); |
1168 | ····················sourcesUpToDate = mapDestTime >= mapSourceTime && mapDestTime >= objTime; |
1169 | ····················// Mapping-Datei muss jünger sein als die bin-Datei |
1170 | ····················if (!projectDescription.IsWebProject && !File.Exists(projectDescription.BinFile)) |
1171 | ························throw new Exception("Can't find binary " + projectDescription.BinFile); |
1172 | ····················DateTime binFileTime = File.GetLastWriteTime(projectDescription.BinFile); |
1173 | ····················if (binFileTime > mapSourceTime) |
1174 | ························sourcesUpToDate = false; |
1175 | ················} |
1176 | ················else |
1177 | ····················sourcesUpToDate = false; |
1178 | ············} |
1179 | |
1180 | ············// Schemadatei muss nach der letzten Kompilierung erzeugt worden sein |
1181 | #if DEBUG |
1182 | ············sourcesUpToDate = false; |
1183 | #endif |
1184 | ············if (sourcesUpToDate) |
1185 | ············{ |
1186 | ················if (File.Exists(schemaFile)) |
1187 | ················{ |
1188 | ····················if (File.GetLastWriteTime(schemaFile) >= objTime) |
1189 | ························return; |
1190 | ················} |
1191 | ············} |
1192 | ············ |
1193 | ············if (options.DefaultConnection != string.Empty) |
1194 | ············{ |
1195 | ················Connection.StandardConnection.Name = options.DefaultConnection; |
1196 | ················Connection.StandardConnection.Type = options.SQLScriptLanguage; |
1197 | ············} |
1198 | ············else |
1199 | ············{ |
1200 | ················Connection.StandardConnection.Name = Connection.DummyConnectionString; |
1201 | ············} |
1202 | |
1203 | ············string wrongDll = null; |
1204 | |
1205 | ············try |
1206 | ············{ |
1207 | ················if (options.NewMapping) |
1208 | ····················File.Delete(mappingFile); |
1209 | ················if (this.verboseMode) |
1210 | ····················messages.WriteLine("Mapping file is: " + mappingFile); |
1211 | |
1212 | #if !STD |
1213 | ················try |
1214 | ················{ |
1215 | #endif |
1216 | ····················mappings = new NDOMapping(mappingFile); |
1217 | ····················mappings.SchemaVersion = options.SchemaVersion; |
1218 | ····················((IEnhancerSupport)mappings).IsEnhancing = true; |
1219 | #if !STD |
1220 | ················} |
1221 | ················catch (ArgumentOutOfRangeException ex) |
1222 | ················{ |
1223 | ····················if (ex.Source == "System.Collections") |
1224 | ························throw new Exception("Too much elements for Community edition: max. 1 connection, 10 classes, 500 objects, 8 relations per class, 8 fields per class are allowed."); |
1225 | ····················else |
1226 | ························throw ex; |
1227 | ················} |
1228 | #endif |
1229 | //#if !STD |
1230 | //················Type t = mappings.Classes.GetType(); |
1231 | //················NDOAssemblyName an = new NDOAssemblyName(t.Assembly.FullName); |
1232 | //················if (an.Name != "System.Collections") |
1233 | //················{ |
1234 | //····················wrongDll = Decryptor.Decrypt(NDOErrors.WrongDll); |
1235 | //················} |
1236 | //#endif |
1237 | ············} |
1238 | #if !STD |
1239 | ············catch (ArgumentOutOfRangeException ex) |
1240 | ············{ |
1241 | ················throw new Exception(Decryptor.Decrypt(NDOErrors.TooMuchElements)); |
1242 | ············} |
1243 | #endif |
1244 | ············catch (Exception ex) |
1245 | ············{ |
1246 | ················if (null != ex.Message) |
1247 | ····················throw new Exception("Can't load Mapping File " + mappingFile + ".\n" + ex.ToString()); |
1248 | ················else |
1249 | ····················throw new Exception("Can't load Mapping File " + mappingFile); |
1250 | ············} |
1251 | |
1252 | ············if (wrongDll != null) |
1253 | ················throw new Exception(wrongDll); |
1254 | |
1255 | ············dsSchema = new NDODataSet(); |
1256 | ············dsSchema.EnforceConstraints = false; |
1257 | |
1258 | ············// The mapping und schema files |
1259 | ············// will be merged here |
1260 | ············searchPersistentBases(); |
1261 | ············bool doEnhance = options.EnableEnhancer && !this.isEnhanced; |
1262 | #if xDEBUG |
1263 | ············doEnhance = options.EnableEnhancer; |
1264 | #endif |
1265 | ············if (this.verboseMode) |
1266 | ············{ |
1267 | ················messages.WriteLine(options.EnableEnhancer ? "Enhancer enabled" : "Enhancer disabled"); |
1268 | ················if (doEnhance) |
1269 | ····················messages.WriteLine(this.isEnhanced ? "Assembly is already enhanced" : "Assembly is not yet enhanced"); |
1270 | ················else |
1271 | ····················messages.WriteLine("Assembly won't be enhanced"); |
1272 | ············} |
1273 | ············if (doEnhance) |
1274 | ············{ |
1275 | ················// Hier wird ILDasm bemüht, um einen Dump des Assemblies herzustellen |
1276 | ················disassemble(); |
1277 | |
1278 | ················ILFile ilfile = new ILFile(); |
1279 | |
1280 | ················messages.WriteLine( "Enhancing Assembly" ); |
1281 | ················messages.Indent(); |
1282 | |
1283 | ················// Hier wird der Elementbaum erzeugt |
1284 | ················ilfile.parse( ilFileName ); |
1285 | ················ILAssemblyElement.Iterator assit = ilfile.getAssemblyIterator(); |
1286 | ················ILAssemblyElement el; |
1287 | ················if (projectDescription.KeyFile == string.Empty) |
1288 | ····················this.assemblyKeyFile = null; |
1289 | ················else |
1290 | ····················this.assemblyKeyFile = projectDescription.KeyFile; |
1291 | ················for (el = assit.getNext(); el != null; el = assit.getNext() ) |
1292 | ················{ |
1293 | ····················if (!el.isExtern()) |
1294 | ····················{ |
1295 | ························ILCustomElement.Iterator cusit = el.getCustomIterator(); |
1296 | ························ILCustomElement custEl; |
1297 | ························for (custEl = cusit.getNext(); custEl != null; custEl = cusit.getNext()) |
1298 | ························{ |
1299 | ····························ILCustomElement.AttributeInfo ai = custEl.getAttributeInfo(); |
1300 | ····························if (ai.Name == "System.Reflection.AssemblyKeyAttribute") |
1301 | ····························{ |
1302 | ································string s = (string) ai.ParamValues[0]; |
1303 | ································if (s != null && s != string.Empty) |
1304 | ································{ |
1305 | ····································this.assemblyKeyFile = ("@" + s); |
1306 | ····································break; |
1307 | ································} |
1308 | ····························} |
1309 | ····························if (ai.Name == "System.Reflection.AssemblyKeyFileAttribute") |
1310 | ····························{ |
1311 | ································string s = (string) ai.ParamValues[0]; |
1312 | ································if (s != null && s != string.Empty) |
1313 | ································{ |
1314 | ····································string fn; |
1315 | ····································if (s.IndexOf(@":\") == -1) |
1316 | ········································fn = CombinePath(this.objPath, s); |
1317 | ····································else |
1318 | ········································fn = s; |
1319 | ····································if (File.Exists(fn)) |
1320 | ········································this.assemblyKeyFile = fn; |
1321 | ····································break; |
1322 | ································} |
1323 | ····························} |
1324 | ························} |
1325 | ························if (this.assemblyKeyFile != null) |
1326 | ····························break; |
1327 | ····················} |
1328 | ················} |
1329 | |
1330 | ················//mergeValueTypes(ilfile); |
1331 | |
1332 | ················analyzeAndEnhance(ilfile); |
1333 | |
1334 | ················messages.Unindent(); |
1335 | ················if (this.verboseMode) |
1336 | ····················messages.WriteLine( "Generating Binary" ); |
1337 | ···················· |
1338 | ················// Hier wird der enhanced Elementbaum als IL-Datei geschrieben |
1339 | ················ilfile.write( ilEnhFile, Corlib.FxType == FxType.Standard2 ); |
1340 | |
1341 | ················// ILAsm assembliert das Ganze |
1342 | ················reassemble(); |
1343 | ············} |
1344 | |
1345 | |
1346 | ············// Store the mapping information |
1347 | ············if (this.verboseMode) |
1348 | ················messages.WriteLine( "Saving mapping file" ); |
1349 | ············mappings.Save(); |
1350 | ············if (verboseMode) |
1351 | ················Console.WriteLine("Copying mapping file to '" + mappingDestFile + "'"); |
1352 | ············File.Copy(mappingFile, mappingDestFile, true); |
1353 | |
1354 | ············if (this.verboseMode) |
1355 | ················messages.WriteLine( "Generating schema file" ); |
1356 | ············if (File.Exists(schemaFile)) |
1357 | ················File.Copy(schemaFile, schemaFile.Replace(".ndo.xsd", ".ndo.xsd.bak"), true); |
1358 | ············dsSchema.WriteXmlSchema(schemaFile); |
1359 | |
1360 | ············if (options.GenerateSQL) |
1361 | ············{ |
1362 | ················if (this.verboseMode) |
1363 | ····················messages.WriteLine( "Generating sql file" ); |
1364 | ················string sqlFileName = schemaFile.Replace(".xsd", ".sql"); |
1365 | ················TypeManager tm = null; |
1366 | ················if (options.IncludeTypecodes) |
1367 | ················{ |
1368 | ····················string typeFile = Path.Combine(Path.GetDirectoryName(binFile), "NDOTypes.Xml"); |
1369 | ····················tm = new TypeManager(typeFile, this.mappings); |
1370 | ················} |
1371 | ················string oldSchemaFile = schemaFile.Replace(".ndo.xsd", ".ndo.xsd.bak"); |
1372 | ················NDODataSet dsOld = null; |
1373 | ················if (File.Exists(oldSchemaFile)) |
1374 | ················{ |
1375 | ····················dsOld = new NDODataSet(oldSchemaFile); |
1376 | ····················new SQLDiffGenerator().Generate(options.SQLScriptLanguage, options.Utf8Encoding, dsSchema, dsOld, sqlFileName, mappings, messages); |
1377 | ····················new NdoTransDiffGenerator().Generate(dsSchema, dsOld, sqlFileName, mappings, messages); |
1378 | ················} |
1379 | ················else |
1380 | ················{ |
1381 | ····················new NdoTransDiffGenerator().Generate( dsSchema, new DataSet(), sqlFileName, mappings, messages ); |
1382 | ················} |
1383 | ················if (!this.options.DropExistingElements) |
1384 | ····················dsOld = null;··// causes, that no drop statements will be generated. |
1385 | ················new SQLGenerator().Generate(options.SQLScriptLanguage, options.Utf8Encoding, dsSchema, dsOld, sqlFileName, mappings, messages, tm, this.options.GenerateConstraints); |
1386 | ············} |
1387 | |
1388 | ········} |
1389 | |
1390 | ········void analyzeAndEnhance( ILFile ilFile ) |
1391 | ········{············ |
1392 | ············IList classes = ilFile.getAllClassElements(); |
1393 | |
1394 | ············if (!isEnhanced) |
1395 | ············{ |
1396 | ················IList foreignAssemblies = checkRelationTargetAssemblies(); |
1397 | |
1398 | ················ILAssemblyElement.Iterator ai = ilFile.getAssemblyIterator(); |
1399 | ················bool insertData = true; |
1400 | ················bool insertXml = true; |
1401 | ················bool insertNdo = true; |
1402 | ················bool insertNdoInterfaces = true; |
1403 | ················bool insertSystem = true; |
1404 | |
1405 | ················for ( ILAssemblyElement assElem = ai.getNext(); null != assElem; assElem = ai.getNext() ) |
1406 | ················{ |
1407 | ····················string nameLower = assElem.getName().ToLower(); |
1408 | ····················if (foreignAssemblies.Contains(assElem.getName())) |
1409 | ························foreignAssemblies.Remove(assElem.getName()); |
1410 | ····················string line = assElem.getLine(0); |
1411 | ····················if (!assElem.isExtern()) |
1412 | ····················{ |
1413 | ························ILElement lastEl = assElem.getCustomIterator().getLast(); |
1414 | ························lastEl.insertBefore(new ILCustomElement(".custom instance void [NDO]NDO.NDOEnhancedAttribute::.ctor() = ( 01 00 00 00 )", assElem)); |
1415 | ····················} |
1416 | ····················if (line.StartsWith(".assembly")) |
1417 | ····················{ |
1418 | ························if (nameLower == "system.data") |
1419 | ····························insertData = false; |
1420 | ························if (nameLower == "system.xml") |
1421 | ····························insertXml = false; |
1422 | ························if (nameLower == "system") |
1423 | ····························insertSystem = false; |
1424 | ························if (nameLower == "ndo") |
1425 | ························{ |
1426 | ····························if (this.verboseMode) |
1427 | ····························{ |
1428 | ································messages.WriteLine("NDO Dll:"); |
1429 | ································ILElementIterator it = assElem.getAllIterator(true); |
1430 | ································for (ILElement subEl = it.getFirst(); subEl != null; subEl = it.getNext()) |
1431 | ····································messages.WriteInsertedLine(subEl.getAllLines()); |
1432 | ····························} |
1433 | ····························insertNdo = false; |
1434 | |
1435 | ····························/* We don't need a version check anymore. This might be necessary again, if it comes to .NET Version 5 |
1436 | ····························if (assElem.Major != 2 && assElem.Minor != 0) |
1437 | ····························{ |
1438 | ································string version = EnhDate.String; |
1439 | ································Regex regex = new Regex( @"V\. (\d+\.\d+)" ); |
1440 | ································Match match = regex.Match( version ); |
1441 | ································if (match.Success) |
1442 | ····································version = match.Groups[1].Value; |
1443 | ································throw new Exception("This assembly is built with NDO.dll Version " + assElem.VersionString.Replace(':', '.') |
1444 | ····································+ ". This NDO enhancer only works with NDO.dll version " + version + ". Please correct your assembly reference and rebuild the assembly."); |
1445 | ····························} |
1446 | ····························*/ |
1447 | #if NDO12 |
1448 | ····························if (assElem.Major != 1 && assElem.Minor != 2) |
1449 | ····························{ |
1450 | ································throw new Exception("This assembly is built with NDO.dll Version " + assElem.VersionString.Replace(':', '.') |
1451 | ····································+ ". This NDO enhancer only works with NDO.dll version 1.2. Please correct your assembly reference and rebuild the assembly."); |
1452 | ····························} |
1453 | #endif |
1454 | #if NDO11 |
1455 | ····························if (assElem.Major != 1 && assElem.Minor != 1) |
1456 | ····························{ |
1457 | ································throw new Exception("This assembly is built with NDO.dll Version " + assElem.VersionString.Replace(':', '.') |
1458 | ····································+ ". This NDO enhancer only works with NDO.dll version 1.1. Please correct your assembly reference and rebuild the assembly."); |
1459 | ····························}······················ |
1460 | #endif |
1461 | ························} |
1462 | ························if (nameLower == "ndointerfaces") |
1463 | ························{ |
1464 | ····························insertNdoInterfaces = false; |
1465 | #if NDO12 |
1466 | ····························if (assElem.Major != 1 && assElem.Minor != 2) |
1467 | ····························{ |
1468 | ································throw new Exception("This assembly is built with NDOInterfaces.dll Version " + assElem.VersionString.Replace(':', '.') |
1469 | ····································+ ". This NDO enhancer only works with NDOInterfaces.dll version > 1.2. Please correct your assembly reference and rebuild the assembly."); |
1470 | ····························} |
1471 | #endif |
1472 | #if NDO11 |
1473 | ····························if (assElem.Major != 1 && assElem.Minor != 1) |
1474 | ····························{ |
1475 | ································throw new Exception("This assembly is built with NDOInterfaces.dll Version " + assElem.VersionString.Replace(':', '.') |
1476 | ····································+ ". This NDO enhancer only works with NDOInterfaces.dll version 1.1. Please correct your assembly reference and rebuild the assembly."); |
1477 | ····························}······················ |
1478 | #endif |
1479 | ························} |
1480 | ····················} |
1481 | #if DEBUG |
1482 | ····················else |
1483 | ····················{ |
1484 | ························throw new Exception("Assembly element doesn't start with .assembly."); |
1485 | ····················} |
1486 | #endif |
1487 | ················} |
1488 | |
1489 | ················ai = ilFile.getAssemblyIterator(); |
1490 | ················ILAssemblyElement ael = ai.getNext(); |
1491 | ················//················string verString; |
1492 | |
1493 | |
1494 | ················if (insertData) |
1495 | ················{ |
1496 | #if NET20 |
1497 | ····················string line = @".assembly extern System.Data |
1498 | { |
1499 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1500 | .ver 2:0:0:0 |
1501 | } |
1502 | "; |
1503 | #else |
1504 | ····················string line = @".assembly extern System.Data |
1505 | { |
1506 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1507 | .ver 1:0:3300:0 |
1508 | } |
1509 | "; |
1510 | #endif |
1511 | ····················ael.insertBefore(new ILElement(line)); |
1512 | ················} |
1513 | |
1514 | ················if (insertSystem) |
1515 | ················{ |
1516 | #if NET20 |
1517 | ····················string line = @".assembly extern System |
1518 | { |
1519 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1520 | .ver 2:0:0:0 |
1521 | } |
1522 | "; |
1523 | #else |
1524 | ····················string line = @".assembly extern System |
1525 | { |
1526 | ··.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1527 | ··.ver 1:0:5000:0 |
1528 | } |
1529 | "; |
1530 | #endif |
1531 | ····················ael.insertBefore(new ILElement(line)); |
1532 | ················} |
1533 | |
1534 | ················if (insertXml) |
1535 | ················{ |
1536 | //····················Assembly ass = Assembly.GetAssembly(typeof(System.Data.DataRow)); |
1537 | //····················verString = getAssemblyInfo(ass, "Version=", ""); |
1538 | //····················verString = ".ver " + verString.Replace(".", ":"); |
1539 | #if NET20 |
1540 | ····················string line = @".assembly extern System.Xml |
1541 | { |
1542 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1543 | .ver 2:0:0:0 |
1544 | } |
1545 | "; |
1546 | #else |
1547 | ····················string line = @".assembly extern System.Xml |
1548 | { |
1549 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1550 | .ver 1:0:3300:0 |
1551 | } |
1552 | "; |
1553 | #endif |
1554 | ····················ael.insertBefore(new ILElement(line)); |
1555 | ················} |
1556 | |
1557 | ················if (insertNdo) |
1558 | ················{ |
1559 | ····················string fullName = typeof(NDOPersistentAttribute).Assembly.FullName; |
1560 | ····················NDOAssemblyName assName = new NDOAssemblyName(fullName); |
1561 | ····················messages.WriteLine("Inserting reference to NDO assembly: " + fullName); |
1562 | ····················string line = @".assembly extern NDO |
1563 | { |
1564 | .publickeytoken = (" + assName.PublicKeyTokenBytes + @") |
1565 | .ver " + assName.Version.Replace(".", ":") + @" |
1566 | } |
1567 | "; |
1568 | |
1569 | ····················ael.insertBefore(new ILElement(line)); |
1570 | ················} |
1571 | |
1572 | ················if (insertNdoInterfaces) |
1573 | ················{ |
1574 | ····················NDOAssemblyName assName = new NDOAssemblyName(typeof(NDOException).Assembly.FullName); |
1575 | ····················string line = @".assembly extern NDOInterfaces |
1576 | { |
1577 | .publickeytoken = (" + assName.PublicKeyTokenBytes + @") |
1578 | .ver " + assName.Version.Replace(".", ":") + @" |
1579 | } |
1580 | "; |
1581 | |
1582 | ····················ael.insertBefore(new ILElement(line)); |
1583 | ················} |
1584 | |
1585 | ················foreach(string s in foreignAssemblies) |
1586 | ················{ |
1587 | ····················string fullName = (string) assemblyFullNames[s]; |
1588 | ····················if (fullName == null) |
1589 | ····················{ |
1590 | ························messages.WriteLine("*** Can't find assembly with name '" + s + "' to be inserted as an assembly reference."); |
1591 | ························continue; |
1592 | ····················} |
1593 | ····················else |
1594 | ····················{ |
1595 | ························if (verboseMode) |
1596 | ····························messages.WriteLine("Insert reference to assembly " + fullName); |
1597 | ····················} |
1598 | |
1599 | ····················NDOAssemblyName assName = new NDOAssemblyName(fullName); |
1600 | ····················string publicKeyToken = string.Empty; |
1601 | ····················if (assName.PublicKeyToken != "null") |
1602 | ························publicKeyToken = ".publickeytoken = (" + assName.PublicKeyTokenBytes + ")\n"; |
1603 | ····················string line = @".assembly extern " + assName.Name + @" |
1604 | { |
1605 | " + publicKeyToken + @" |
1606 | .ver " + assName.Version.Replace(".", ":") + @" |
1607 | } |
1608 | "; |
1609 | |
1610 | ····················ael.insertBefore(new ILElement(line)); |
1611 | ···················· |
1612 | ················} |
1613 | |
1614 | ············} // !enhanced············ |
1615 | |
1616 | ············// Jetzt alle Klassen durchlaufen und ggf. Enhancen |
1617 | ············foreach ( ILClassElement classElement in··classes ) |
1618 | ············{ |
1619 | ················if (classElement.isPersistent(typeof (NDOPersistentAttribute))) |
1620 | ················{ |
1621 | ····················Dictionary<string, string> accessors = classElement.findAccessorProperties(); |
1622 | ····················Class classMapping = mappings.FindClass( classElement.getMappingName() ); |
1623 | ····················if (classMapping != null && accessors.Count > 0) |
1624 | ····················{ |
1625 | ························foreach (var item in accessors) |
1626 | ························{ |
1627 | ····························Field field = classMapping.FindField( item.Key ); |
1628 | ····························if (field != null) |
1629 | ····························{ |
1630 | ································field.AccessorName = item.Value; |
1631 | ····························} |
1632 | ····························else |
1633 | ····························{ |
1634 | ································Relation rel = classMapping.FindRelation( item.Key ); |
1635 | ································if (rel != null) |
1636 | ····································rel.AccessorName = item.Value; |
1637 | ····························} |
1638 | ························} |
1639 | ····················} |
1640 | ····················string mappingName = classElement.getMappingName(); |
1641 | ····················IList sortedFields = (IList) allSortedFields[mappingName]; |
1642 | ····················IList references = (IList) allReferences[mappingName]; |
1643 | ····················Patcher.ClassPatcher cls = new Patcher.ClassPatcher( classElement, mappings, allPersistentClasses, messages, sortedFields, references, this.oidTypeName ); |
1644 | ····················if (!isEnhanced) |
1645 | ····················{ |
1646 | ························// Klasse enhancen |
1647 | ························cls.enhance(); |
1648 | ····················} |
1649 | ················} |
1650 | ············}············ |
1651 | ········} |
1652 | |
1653 | |
1654 | |
1655 | |
1656 | ········private void |
1657 | ········disassemble() |
1658 | ········{ |
1659 | ············Dasm dasm = new Dasm(messages, this.verboseMode); |
1660 | ············dasm.DoIt(objFile, ilFileName); |
1661 | ············if (File.Exists(resFile)) |
1662 | ············{ |
1663 | ················File.Copy(resFile, resEnhFile, true); |
1664 | ················File.Delete(resFile); |
1665 | ············} |
1666 | ········} |
1667 | |
1668 | ········private void |
1669 | ········reassemble() |
1670 | ········{ |
1671 | ············Asm asm = new Asm(messages, this.verboseMode); |
1672 | ············if (this.verboseMode) |
1673 | ················messages.WriteLine("KeyFile: " + this.assemblyKeyFile); |
1674 | |
1675 | ············asm.DoIt(ilEnhFile, enhFile, this.assemblyKeyFile, debug); |
1676 | ············if (! File.Exists(enhFile)) |
1677 | ····················throw new Exception("Codeerzeugung: temporäre Datei " + enhFile + " konnte nicht erstellt werden."); |
1678 | ············string resFile = Path.ChangeExtension(enhFile, ".res"); |
1679 | ············if (File.Exists(resFile)) |
1680 | ················File.Delete(resFile); |
1681 | //············File.Copy( enhFile, binFile, true ); |
1682 | |
1683 | ············DateTime ct = File.GetCreationTime(objFile); |
1684 | ············DateTime at = File.GetLastAccessTime(objFile); |
1685 | ············DateTime wt = File.GetLastWriteTime(objFile); |
1686 | ············ |
1687 | //············File.Copy( enhFile, objFile, true ); |
1688 | |
1689 | ············File.SetCreationTime(enhFile, ct); |
1690 | ············File.SetLastAccessTime(enhFile, at); |
1691 | ············File.SetLastWriteTime(enhFile, wt); |
1692 | |
1693 | //············if ( debug ) |
1694 | //············{ |
1695 | //················if (! File.Exists(enhPdbFile)) |
1696 | //····················throw new Exception("Codeerzeugung: temporäre Datei " + enhPdbFile + " konnte nicht erstellt werden."); |
1697 | //················File.Copy( enhPdbFile, binPdbFile, true ); |
1698 | //············} |
1699 | |
1700 | ········} |
1701 | |
1702 | ····} |
1703 | } |
1704 |
New Commit (dff5303)
1 | // |
2 | // Copyright (c) 2002-2016 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.RegularExpressions; |
25 | using System.IO; |
26 | using System.Diagnostics; |
27 | using System.Collections; |
28 | using System.Collections.Generic; |
29 | using System.Linq; |
30 | using System.Xml; |
31 | using System.Data; |
32 | using Microsoft.Win32; |
33 | |
34 | using NDO; |
35 | using NDO.Mapping; |
36 | using NDO.Mapping.Attributes; |
37 | |
38 | using ILCode; |
39 | using System.Reflection; |
40 | |
41 | |
42 | namespace NDOEnhancer |
43 | { |
44 | ····/// <summary> |
45 | ····/// Der ganze Enhancement-Prozess beginnt bei DoIt() |
46 | ····/// </summary> |
47 | ····internal class Enhancer |
48 | ····{ |
49 | ········public |
50 | ············Enhancer( ProjectDescription projectDescription, MessageAdapter messages ) |
51 | ········{ |
52 | ············this.projectDescription····= projectDescription; |
53 | ············this.debug········= projectDescription.Debug; |
54 | ············this.binFile····= projectDescription.BinFile; |
55 | ············this.objPath····= projectDescription.ObjPath; |
56 | ············this.messages····= messages; |
57 | |
58 | ············binPdbFile = Path.Combine(Path.GetDirectoryName( binFile ), Path.GetFileNameWithoutExtension( binFile ) + ".pdb"); |
59 | ············tempDir = Path.Combine(objPath, "ndotemp"); |
60 | ············if (!Directory.Exists(tempDir)) |
61 | ················Directory.CreateDirectory(tempDir); |
62 | ············string fileWithoutExtension = Path.GetFileNameWithoutExtension(binFile); |
63 | ············ilFileName···· = Path.Combine(tempDir, fileWithoutExtension + ".org.il"); |
64 | ············resFile = Path.Combine(tempDir, fileWithoutExtension + ".org.res"); |
65 | ············resEnhFile = Path.Combine(tempDir, fileWithoutExtension + ".res"); |
66 | ············ilEnhFile = Path.Combine(tempDir, fileWithoutExtension + ".il"); |
67 | ············objFile = Path.Combine(objPath, Path.GetFileName(binFile)); |
68 | ············enhFile = Path.Combine(tempDir, Path.GetFileName(binFile)); |
69 | ············enhPdbFile = Path.Combine(tempDir, fileWithoutExtension + ".pdb"); |
70 | ············projPath = projectDescription.ProjPath; |
71 | ············schemaFile = Path.Combine(Path.GetDirectoryName(binFile), fileWithoutExtension + ".ndo.xsd"); |
72 | ············mappingDestFile = Path.Combine(Path.GetDirectoryName( binFile ), projectDescription.ConfigurationOptions.TargetMappingFileName); |
73 | ············mappingFile = projectDescription.DefaultMappingFileName; |
74 | ············options = projectDescription.ConfigurationOptions; |
75 | |
76 | ············//············foreach (EnvDTE.Property p in project.Properties) |
77 | ············//················messages.WriteLine("··" + p.Name + " " + p.Value.ToString()); |
78 | |
79 | ········} |
80 | |
81 | ········private ProjectDescription····projectDescription; |
82 | ········private bool················debug; |
83 | ········private bool················isEnhanced; |
84 | ········private bool················verboseMode; |
85 | ········private string················oidTypeName = null; |
86 | ········private bool················hasPersistentClasses; |
87 | ········private string················binFile; |
88 | ········private string················binPdbFile; |
89 | ········private string················objPath; |
90 | ········private string··············tempDir; |
91 | ········private string··············projPath; |
92 | |
93 | ········private string················ilFileName; |
94 | ········private string················resFile; |
95 | ········private string··············resEnhFile; |
96 | ········private string··············ilEnhFile; |
97 | ········private string················objFile; |
98 | ········private string················enhFile; |
99 | ········private string················enhPdbFile; |
100 | ········private string················schemaFile; |
101 | ········private string················mappingDestFile; |
102 | ········private string················mappingFile; |
103 | ········private string················ownAssemblyName = null; |
104 | ········private StreamWriter········sortedFieldsFile; |
105 | |
106 | ········private ClassHashtable········allPersistentClasses = new ClassHashtable(); |
107 | ········private Hashtable············allSortedFields = new ClassHashtable(); |
108 | ········private Hashtable············allReferences = new ClassHashtable(); |
109 | ········private Hashtable············assemblyFullNames = new Hashtable(); |
110 | ········private IList················tabuClasses = new ArrayList(); |
111 | ········private NDOMapping··········mappings; |
112 | ········private MessageAdapter········messages; |
113 | ········private NDODataSet············dsSchema; |
114 | ········private ConfigurationOptions options; |
115 | ········private string················assemblyKeyFile = null; |
116 | |
117 | ········private static string assemblyPath = null; |
118 | |
119 | |
120 | ········public static string AssemblyPath |
121 | ········{ |
122 | ············get |
123 | ············{ |
124 | ················if (null == assemblyPath) |
125 | ················{ |
126 | ····················RegistryKey key = Registry.LocalMachine.OpenSubKey( @"SOFTWARE\NDO" ); |
127 | ····················if ( key == null ) |
128 | ························throw new Exception( @"Can't find NDO in the registry at HKLM\SOFTWARE\NDO. Please reinstall NDO." ); |
129 | ····················assemblyPath = (string) key.GetValue( "InstallDir" ); |
130 | ····················if ( assemblyPath == null ) |
131 | ························throw new Exception( @"Can't find InstallDir value in the registry at HKLM\SOFTWARE\NDO. Please reinstall NDO." ); |
132 | ················} |
133 | ················return assemblyPath; |
134 | ············} |
135 | ········} |
136 | |
137 | ········void CheckNDO(Assembly ass) |
138 | ········{ |
139 | ·· //········ AssemblyName[] references = ass.GetReferencedAssemblies(); |
140 | ·· //········ NDOAssemblyName refAn = null; |
141 | ·· //········ foreach (AssemblyName an in references) |
142 | ·· //········ { |
143 | ·· //············ if (an.Name == "NDO") |
144 | ·· //················ refAn = new NDOAssemblyName(an.FullName); |
145 | ············//} |
146 | ·· //········ if (refAn == null) |
147 | ·· //············ return; |
148 | ·· //········ NDOAssemblyName ndoAn = new NDOAssemblyName(typeof(NDOPersistentAttribute).Assembly.FullName);··// give us the NDO version the enhancer belongs to |
149 | ············//Version refVersion = refAn.AssemblyVersion; |
150 | ············//bool isRightVersion = refVersion.Major > 2 || refVersion.Major == 2 && refVersion.Minor >= 1; |
151 | ·· //········ if (refAn.PublicKeyToken != ndoAn.PublicKeyToken || !isRightVersion) |
152 | ·· //········ { |
153 | ·· //············ throw new Exception("Assembly " + ass.FullName + " references a wrong NDO.dll. Expected: " + ndoAn.FullName + ". Found: " + refAn.FullName + "."); |
154 | ·· //········ }·· |
155 | ········} |
156 | |
157 | |
158 | ········private void |
159 | ············searchPersistentBases() |
160 | ········{ |
161 | ············Dictionary<string, NDOReference> references = projectDescription.References; |
162 | ············ArrayList ownClassList = null; |
163 | ············string binaryAssemblyFullName = null; |
164 | |
165 | ············if (!projectDescription.IsWebProject) |
166 | ············{ |
167 | ················// Check, if we can load the project bin file. |
168 | ················try |
169 | ················{ |
170 | ····················binaryAssemblyFullName = NDOAssemblyChecker.GetAssemblyName(this.binFile); |
171 | ················} |
172 | ················catch (Exception ex) |
173 | ················{ |
174 | ····················throw new Exception("Can't load referenced Assembly '" + this.binFile + ". " + ex.Message); |
175 | ················} |
176 | ············} |
177 | |
178 | ············// Durchsuche alle referenzierten Assemblies |
179 | ············foreach (NDOReference reference in references.Values) |
180 | ············{ |
181 | ················if ( !reference.CheckThisDLL ) |
182 | ····················continue; |
183 | |
184 | ················string dllPath = reference.Path; |
185 | ················bool ownAssembly = (string.Compare( dllPath, this.binFile, true ) == 0); |
186 | |
187 | ················if (!ownAssembly && !NDOAssemblyChecker.IsEnhanced( dllPath )) |
188 | ····················continue; |
189 | |
190 | ················AssemblyName assToLoad = null; |
191 | ················Assembly ass = null; |
192 | ················try |
193 | ················{ |
194 | ····················if (verboseMode) |
195 | ························messages.WriteLine($"Loading assembly {dllPath}"); |
196 | ····················assToLoad = AssemblyName.GetAssemblyName(dllPath); |
197 | ····················ass = Assembly.Load(assToLoad); |
198 | ················} |
199 | ················catch (Exception ex) |
200 | ················{ |
201 | ····················if (assToLoad != null && (binaryAssemblyFullName == null || string.Compare(binaryAssemblyFullName, assToLoad.FullName, true) != 0)) |
202 | ····················{ |
203 | ························// Not bin file - enhancer may work, if assembly doesn't contain |
204 | ························// persistent classes. |
205 | ························messages.WriteLine("Can't load referenced Assembly '" + dllPath +". The enhancer may not work correctly."); |
206 | ····················} |
207 | ····················else |
208 | ····················{ |
209 | ························throw new Exception("Can't load referenced Assembly '" + projectDescription.BinFile + ". " + ex.Message); |
210 | ····················} |
211 | ····················continue; |
212 | ················} |
213 | |
214 | ················string assName = assToLoad.Name; |
215 | ················if (this.assemblyFullNames.Contains(assName)) |
216 | ················{ |
217 | ····················messages.WriteLine("Assembly '" + assName + "' analyzed twice. Check your .ndoproj file."); |
218 | ····················continue; |
219 | ················} |
220 | ················this.assemblyFullNames.Add(assName, assToLoad.FullName); |
221 | |
222 | ················if (verboseMode) |
223 | ················{ |
224 | ····················messages.WriteLine("Checking DLL: " + dllPath); |
225 | ····················messages.WriteLine("BinFile: " + binFile); |
226 | ················} |
227 | |
228 | ················AssemblyNode assemblyNode = null; |
229 | ················CheckNDO(ass); |
230 | |
231 | ················try |
232 | ················{ |
233 | ····················assemblyNode = new AssemblyNode(ass, this.mappings); |
234 | ················} |
235 | ················catch (Exception ex) |
236 | ················{ |
237 | ····················if (verboseMode) |
238 | ························messages.ShowError("Error while reflecting types of assembly " + dllPath + ". " + ex); |
239 | ····················else |
240 | ························messages.ShowError("Error while reflecting types of assembly " + dllPath + ". " + ex.Message); |
241 | ················} |
242 | |
243 | ················if (ownAssembly) |
244 | ················{ |
245 | ····················ownClassList = assemblyNode.PersistentClasses; |
246 | ····················this.isEnhanced = assemblyNode.IsEnhanced; |
247 | ····················this.oidTypeName = assemblyNode.OidTypeName; |
248 | ····················this.ownAssemblyName = assName; |
249 | ····················Corlib.FxType = assemblyNode.TargetFramework == ".NETStandard,Version=v2.0" ? FxType.Standard2 : FxType.NetFx; |
250 | ····················if (this.verboseMode) |
251 | ························messages.WriteLine( $"FxType: {ownAssemblyName}: {Corlib.FxType}" ); |
252 | ················} |
253 | |
254 | ················ArrayList classList = assemblyNode.PersistentClasses; |
255 | ················foreach(ClassNode classNode in classList) |
256 | ················{ |
257 | ····················string clName = classNode.Name; |
258 | ····················if (!allPersistentClasses.Contains(clName)) |
259 | ························allPersistentClasses.Add(clName, classNode); |
260 | ····················else if (verboseMode) |
261 | ························messages.WriteLine("Multiple definition of Class " + clName + '.'); |
262 | ················} |
263 | |
264 | ················// Wir haben externe persistente Klassen gefunden. |
265 | ················// Mapping-Info einlesen. |
266 | ················if (!ownAssembly) |
267 | ····················mergeMappingFile(dllPath, classList); |
268 | ················if (!ownAssembly) |
269 | ····················mergeDataSet(dllPath, classList); |
270 | |
271 | ················if (ownAssembly) |
272 | ················{ |
273 | ····················this.hasPersistentClasses = (classList.Count > 0); |
274 | ················} |
275 | |
276 | ················// TODO: Check, how to handle value types |
277 | //················XmlNodeList vtnl = pcDoc.SelectNodes(@"/PersistentClasses/ValueType"); |
278 | //················ValueTypes.Instance.Merge(vtnl); |
279 | ············} |
280 | |
281 | ············if (projectDescription.IsWebProject || !options.EnableEnhancer) |
282 | ············{ |
283 | ················ownClassList = new ArrayList(); |
284 | ············} |
285 | ············else |
286 | ············{ |
287 | ················if (ownClassList == null) |
288 | ····················throw new Exception("A reference to the assembly " + binFile + " is needed. Check your parameter file."); |
289 | ············} |
290 | |
291 | ············checkClassMappings(ownClassList); |
292 | ············checkTypeList(); |
293 | ············checkOidColumnMappings(); // Incorporates the Attributes and NDOOidType. |
294 | ············checkAllRelationMappings(ownClassList); // Makes sure, that a mapping entry for each relation exists |
295 | ············determineOidTypes(); // needs the relation mappings, calls InitFields |
296 | ············checkRelationForeignKeyMappings(); // Calls r.InitFields, therefore requires, that InitFields for the Oid's was called |
297 | ············generateAllSchemas(); |
298 | ············removeRedundantOidColumnNames(); |
299 | ········} |
300 | |
301 | |
302 | ········private void removeRedundantOidColumnNames() |
303 | ········{ |
304 | ············foreach (Class cl in mappings.Classes) |
305 | ············{ |
306 | ················new OidColumnIterator(cl).Iterate(delegate(OidColumn oidColumn, bool isLastElement) |
307 | ················{ |
308 | ····················if (oidColumn.FieldName == string.Empty) |
309 | ························oidColumn.FieldName = null; |
310 | ····················if (oidColumn.RelationName == string.Empty) |
311 | ························oidColumn.RelationName = null; |
312 | ····················if (oidColumn.FieldName != null || oidColumn.RelationName != null) |
313 | ····················{ |
314 | ························oidColumn.Name = null;······// Let the field or relation define the name |
315 | ························oidColumn.NetType = null;·· // Let the field or relation determine the type |
316 | ····················} |
317 | ················}); |
318 | ············} |
319 | ········} |
320 | |
321 | ········private void checkOidColumnMappings() |
322 | ········{ |
323 | ············foreach (Class cl in mappings.Classes) |
324 | ············{ |
325 | |
326 | ················ClassNode classNode = allPersistentClasses[cl.FullName]; |
327 | ················if (classNode == null) |
328 | ················{ |
329 | ····················messages.WriteLine("Warning: can't find ClassNode for class " + cl.FullName); |
330 | ····················continue; |
331 | ················} |
332 | ················ClassOid oid = cl.Oid; |
333 | ················if (oid.OidColumns.Count == 0 && !classNode.ColumnAttributes.Any()) |
334 | ················{ |
335 | ····················OidColumn oidColumn = oid.NewOidColumn(); |
336 | ····················oidColumn.Name = "ID"; |
337 | ················} |
338 | |
339 | ················// Check, if the oid columns match the OidColumnAttributes, if any of them exist |
340 | ················// In case of NDOOidType the ClassNode constructor creates an OidColumnAttribute |
341 | |
342 | ················oid.RemapOidColumns(classNode.ColumnAttributes); |
343 | |
344 | ················bool noNameError = false; |
345 | |
346 | ················new OidColumnIterator(cl).Iterate(delegate(OidColumn oidColumn, bool isLastElement) |
347 | ················{ |
348 | ····················if (string.IsNullOrEmpty(oidColumn.Name) && string.IsNullOrEmpty(oidColumn.FieldName) && string.IsNullOrEmpty(oidColumn.RelationName)) |
349 | ····················{ |
350 | ························noNameError = true; |
351 | ························messages.WriteLine("Error: Oid column of class " + cl.FullName + " doesn't have a column name."); |
352 | ····················} |
353 | ················}); |
354 | ················if (noNameError) |
355 | ····················throw new Exception("If you define several OidColumns with the OidColumnAttribute, you have to assign a name for each column."); |
356 | ············} |
357 | ········} |
358 | |
359 | ········/// <summary> |
360 | ········/// Checks, if all foreign key mapping entries match the oid columns of the target types |
361 | ········/// </summary> |
362 | ········private void checkRelationForeignKeyMappings() |
363 | ········{ |
364 | ············// Now check, if all relations have correct foreign keys |
365 | ············foreach (Class cl in mappings.Classes) |
366 | ············{ |
367 | ················foreach (Relation r in cl.Relations) |
368 | ················{ |
369 | ····················/* |
370 | ···················· * 1. klären, ob ForeignKeyColumns oder ChildForeignKeyColumns relevant sind |
371 | ···················· *······- Multiplicity··Ist die schon bekannt? |
372 | ···················· *······- ChildForeignKeyColumnAttributes |
373 | ···················· *······- r.MappingTable··RelationMappings sollten schon bestimmt sein |
374 | ···················· * 2. Count vergleichen, bei MappingTable auch für eigenen Oid-Typ. Warnung bei != |
375 | ···················· * 3. Bei Bedarf remappen |
376 | ···················· * Präzedenz:·· 1. Attribute |
377 | ···················· *··············2. Mapping File |
378 | ···················· *··············3. Defaults |
379 | ···················· */ |
380 | ····················//Class relClass = allPersistentClasses[r.ReferencedTypeName].Class; |
381 | ····················//if (relClass.Oid.OidColumns != r. |
382 | ····················//r.RemapForeignKeyColumns(); |
383 | ················} |
384 | |
385 | ················foreach (IFieldInitializer fi in cl.Relations) |
386 | ····················fi.InitFields(); |
387 | |
388 | ············} |
389 | ········} |
390 | ················ |
391 | ········private IList checkRelationTargetAssemblies() |
392 | ········{ |
393 | ············ArrayList foreignAssemblies = new ArrayList(); |
394 | ············foreach(Class cl in this.mappings.Classes) |
395 | ············{ |
396 | ················foreach(Relation r in cl.Relations) |
397 | ················{ |
398 | ····················ClassNode classNode = this.allPersistentClasses[r.ReferencedTypeName]; |
399 | ····················if (classNode == null) |
400 | ························throw new InternalException(242, "Enhancer.checkRelationTargetAssemblies"); |
401 | ····················if (classNode.AssemblyName != this.ownAssemblyName) |
402 | ····················{ |
403 | ························if (!foreignAssemblies.Contains(classNode.AssemblyName)) |
404 | ····························foreignAssemblies.Add(classNode.AssemblyName); |
405 | ····················} |
406 | ················} |
407 | ············} |
408 | ············return foreignAssemblies; |
409 | ········} |
410 | ········ |
411 | #if nix·· // should now be done in InitFields |
412 | ········private void checkAllMultiplicities() |
413 | ········{ |
414 | ············foreach(Class cl in mappings.Classes) |
415 | ············{ |
416 | ················foreach(Relation r in cl.Relations) |
417 | ················{ |
418 | ····················// Setting the class with reflection |
419 | ····················RelationNode definingNode = getDefiningNodeForRelation(r); |
420 | ····················if (definingNode == null) // Relation might be deleted |
421 | ························continue; |
422 | ····················Class definingClass = allPersistentClasses[definingNode.Parent.Name].Class; |
423 | ····················SetDefiningClass(r, definingClass); |
424 | |
425 | ····················r.Multiplicity = definingNode.IsElement |
426 | ························? RelationMultiplicity.Element |
427 | ························: RelationMultiplicity.List; |
428 | ················} |
429 | ············} |
430 | ········} |
431 | |
432 | ········private RelationNode getDefiningNodeForRelation(Relation r) |
433 | ········{ |
434 | ············ClassNode classNode = allPersistentClasses[r.Parent.FullName]; |
435 | ············if (classNode == null) |
436 | ················throw new InternalException(239, "Enhancer: getDefiningClassForRelation; can't find ClassNode for " + r.Parent.FullName); |
437 | |
438 | ············while (classNode != null) |
439 | ············{ |
440 | ················foreach(RelationNode rn in classNode.Relations) |
441 | ····················if (rn.Name == r.FieldName) |
442 | ························return rn; |
443 | ················classNode = this.allPersistentClasses[classNode.BaseName]; |
444 | ············} |
445 | ············//throw new Exception("Can't find defining ClassNode for relation " + r.Parent.FullName + "." + r.FieldName + ". Check your mapping file for unnecessary Relation entries."); |
446 | ············return null; // Relation might be deleted |
447 | ········} |
448 | |
449 | #endif |
450 | |
451 | #if PRO |
452 | |
453 | ········private void checkTypeList() |
454 | ········{ |
455 | ············string typeFile = Path.Combine(Path.GetDirectoryName(binFile), "NDOTypes.Xml"); |
456 | ············TypeManager tm = new TypeManager(typeFile, this.mappings); |
457 | ············tm.CheckTypeList(allPersistentClasses); |
458 | ········} |
459 | #endif |
460 | |
461 | ········void generateAllSchemas() |
462 | ········{ |
463 | ············dsSchema.Remap(mappings); |
464 | #if nix |
465 | ············foreach(DictionaryEntry de in this.allPersistentClasses) |
466 | ············{ |
467 | ················ClassNode classNode = (ClassNode) de.Value; |
468 | ················if (classNode.IsAbstractOrInterface) |
469 | ····················continue; |
470 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
471 | ····················continue; |
472 | ················string pureName = classNode.Name; |
473 | ················Class classMapping = classNode.Class; |
474 | ················new SchemaGenerator(classMapping, mappings, dsSchema, messages, allSortedFields, allPersistentClasses, verboseMode).GenerateTables(); |
475 | ············} |
476 | ············foreach(DictionaryEntry de in this.allPersistentClasses) |
477 | ············{ |
478 | ················ClassNode classNode = (ClassNode) de.Value; |
479 | ················if (classNode.IsAbstractOrInterface) |
480 | ····················continue; |
481 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
482 | ····················continue; |
483 | ················string pureName = classNode.Name; |
484 | ················Class classMapping = classNode.Class; |
485 | ················new SchemaGenerator(classMapping, mappings, dsSchema, messages, allSortedFields, allPersistentClasses, verboseMode).GenerateRelations(); |
486 | ············} |
487 | #endif |
488 | ········} |
489 | |
490 | |
491 | |
492 | ········public void |
493 | ········mergeDataSet(string absDllPath, ArrayList classList) |
494 | ········{············ |
495 | ············string dsFile = Path.Combine(Path.GetDirectoryName(absDllPath), Path.GetFileNameWithoutExtension(absDllPath) + ".ndo.xsd"); |
496 | ············if (!File.Exists(dsFile)) |
497 | ················return; |
498 | |
499 | ············NDODataSet dsToMerge = new NDODataSet(dsFile); |
500 | ············foreach(DataTable dt in dsToMerge.Tables) |
501 | ············{ |
502 | ················if (null == dsSchema.Tables[dt.TableName]) |
503 | ················{ |
504 | ····················DataTable newdt = dt.Clone(); |
505 | ····················dsSchema.Tables.Add(newdt); |
506 | ················} |
507 | ············} |
508 | ············foreach(DataRelation dr in dsToMerge.Relations) |
509 | ············{ |
510 | ················if (null == dsSchema.Relations[dr.RelationName]) |
511 | ················{ |
512 | ····················DataRelation newdr = null; |
513 | ····················try |
514 | ····················{ |
515 | ························dsSchema.Relations.Add( newdr = new DataRelation( dr.RelationName, dsSchema.Tables[dr.ParentTable.TableName].Columns[dr.ParentColumns[0].ColumnName], dsSchema.Tables[dr.ChildTable.TableName].Columns[dr.ChildColumns[0].ColumnName], true ) ); |
516 | ····················} |
517 | ····················catch(Exception ex) |
518 | ····················{ |
519 | ························string relName = "null"; |
520 | ························if (dr != null && dr.RelationName != null) |
521 | ····························relName = dr.RelationName; |
522 | |
523 | ························throw new Exception("Error while merging relation '" + relName + "' into the new dataset: " + ex.Message); |
524 | ····················} |
525 | ····················newdr.ChildKeyConstraint.DeleteRule = dr.ChildKeyConstraint.DeleteRule; |
526 | ····················newdr.ChildKeyConstraint.UpdateRule = dr.ChildKeyConstraint.UpdateRule; |
527 | ················} |
528 | ············} |
529 | ········} |
530 | |
531 | #if nix |
532 | ········private void getOidType(FieldNode fieldNode, Class cls) |
533 | ········{ |
534 | ············Type t = fieldNode.OidType; |
535 | ············if (t == null) |
536 | ············{ |
537 | ················messages.WriteLine(String.Format("Invalid Oid type {0} in class {1} - using int instead.", fieldNode.DataType, cls.FullName)); |
538 | ················t = typeof(int); |
539 | ············} |
540 | ············cls.Oid.FieldType = t; |
541 | ········} |
542 | #endif |
543 | ········private void |
544 | ········determineOidTypes() |
545 | ········{ |
546 | ············foreach (Class cl in mappings.Classes) |
547 | ············{ |
548 | ················ClassNode classNode = (ClassNode)allPersistentClasses[cl.FullName]; |
549 | ················if (classNode == null) |
550 | ················{ |
551 | ····················mappings.RemoveClass( cl ); |
552 | ····················continue; |
553 | ················} |
554 | ················cl.IsAbstract = classNode.IsAbstract;··// usually this is set in Class.InitFields, which isn't called by the Enhancer. |
555 | ················cl.SystemType = classNode.ClassType; |
556 | ············} |
557 | ············foreach(Class cl in mappings.Classes) |
558 | ············{ |
559 | ················string className = cl.FullName; |
560 | |
561 | ················// Even abstract types should have an oid type, |
562 | ················// because they can be targets of relations - thus |
563 | ················// we need a foreign key column type. |
564 | |
565 | ················ClassOid oid = cl.Oid; |
566 | ················if (oid == null) |
567 | ····················throw new Exception("MergeOidTypes: Can't find Oid Mapping for class " + className); |
568 | |
569 | #if DEBUG |
570 | ················if (cl.FullName.IndexOf("OrderDetail") > -1) |
571 | ····················Console.WriteLine(); |
572 | #endif |
573 | |
574 | ················((IFieldInitializer)oid).InitFields(); |
575 | ············} |
576 | ········} |
577 | |
578 | |
579 | ········private void checkMappingForField(string prefix, Patcher.ILField field, ArrayList sortedFields, Class classMapping, bool isOnlyChild, FieldNode fieldNode) |
580 | ········{ |
581 | ············bool isOidField = fieldNode.IsOid; |
582 | ············if (field.CleanName.StartsWith("_ndo")) |
583 | ············{ |
584 | ················if (this.verboseMode) |
585 | ····················messages.WriteLine("Warning: **** found _ndo field: " + field.CleanName); |
586 | ················return; |
587 | ············} |
588 | ············string fname = prefix + field.CleanName; |
589 | ············if (field.HasNestedFields) |
590 | ············{ |
591 | ················bool oneChildOnly = field.Fields.Count == 1; |
592 | ················foreach(Patcher.ILField newf in field.Fields) |
593 | ················{ |
594 | ····················checkMappingForField(field.CleanName + ".", newf, sortedFields, classMapping, oneChildOnly, fieldNode); |
595 | ················} |
596 | ················return; |
597 | ············} |
598 | ············DictionaryEntry deToDelete = new DictionaryEntry(string.Empty, string.Empty); |
599 | ············if (field.IsInherited) |
600 | ············{ |
601 | ················foreach(DictionaryEntry de in sortedFields) |
602 | ····················if (de.Key.Equals(fname)) |
603 | ························deToDelete = de; |
604 | ············} |
605 | ············if (((string)deToDelete.Key) != string.Empty) |
606 | ················deToDelete.Value = field; |
607 | ············else |
608 | ················sortedFields.Add(new DictionaryEntry(fname, field)); |
609 | |
610 | ············if (classMapping != null) |
611 | ············{ |
612 | ················Field f = classMapping.FindField(fname); |
613 | ················if (null == f) |
614 | ················{ |
615 | ····················f = classMapping.AddStandardField(fname, isOidField); |
616 | ····················if (isOnlyChild) |
617 | ························f.Column.Name = classMapping.ColumnNameFromFieldName(field.Parent.CleanName, false); |
618 | ····················messages.WriteLine("Generating field mapping: " + classMapping.FullName + "." + fname + " -> " + f.Column.Name); |
619 | ····················if (classMapping.IsAbstract) |
620 | ························f.Column.Name = "Unused"; |
621 | ················} |
622 | ················if (fieldNode.FieldAttribute != null) |
623 | ················{ |
624 | ····················fieldNode.FieldAttribute.SetFieldValues( f ); |
625 | ················} |
626 | ················if (fieldNode.ColumnAttribute != null) |
627 | ················{ |
628 | ····················fieldNode.ColumnAttribute.SetColumnValues( f.Column ); |
629 | ················} |
630 | ············} |
631 | ········} |
632 | |
633 | ········/// <summary> |
634 | ········/// Helps sorting the fields |
635 | ········/// </summary> |
636 | ········private class FieldSorter : IComparer |
637 | ········{ |
638 | ············public int Compare(object x, object y) |
639 | ············{ |
640 | ················if (!(x is DictionaryEntry) || !(y is DictionaryEntry)) |
641 | ····················throw new Exception("Interner Fehler: FieldSorter.Compare: DictionaryEntry erwartet; x= " + x.GetType().FullName + " y = " + y.GetType().FullName); |
642 | ················return String.CompareOrdinal((string)((DictionaryEntry) x).Key, (string)((DictionaryEntry) y).Key); |
643 | ············} |
644 | ········} |
645 | |
646 | |
647 | ········private void IterateFieldNodeList(IList fieldList, bool isEmbeddedObject, |
648 | ············List<FieldNode> oidFields, Class classMapping, ArrayList sortedFields, |
649 | ············bool isInherited) |
650 | ········{ |
651 | ············string tn; |
652 | ············foreach(FieldNode fieldNode in fieldList) |
653 | ············{ |
654 | ················// Beim Anlegen eines Fields werden auch gleich die SubFields angelegt, |
655 | ················// wenn das Field ein Value Type ist |
656 | ················string thename = fieldNode.Name; |
657 | ················tn = fieldNode.DataType; |
658 | ················//Debug.WriteLine(tn); |
659 | ················string pattern = @"(class\s|valuetype\s|)(\[[^\]]+\]|)"; |
660 | ················Regex regex = new Regex(pattern); |
661 | ················Match match = regex.Match(tn); |
662 | ················if (match.Groups[2].Value == "[" + ownAssemblyName + "]") |
663 | ····················tn = tn.Replace(match.Groups[2].Value, ""); |
664 | |
665 | ················if (!isEmbeddedObject && fieldNode.IsOid) |
666 | ····················oidFields.Add(fieldNode); |
667 | ················IList subFieldList = null; |
668 | ················if (isEmbeddedObject) |
669 | ················{ |
670 | ····················subFieldList = fieldNode.Fields; |
671 | ················} |
672 | |
673 | ················bool isEnum = (fieldNode.IsEnum); |
674 | ················Patcher.ILField field = new Patcher.ILField(fieldNode.FieldType, tn, |
675 | ····················fieldNode.Name, this.ownAssemblyName, subFieldList, isEnum); |
676 | ················field.IsInherited = isInherited; |
677 | ················System.Diagnostics.Debug.Assert (field.Valid, "field.Valid is false"); |
678 | ················if (classMapping != null) |
679 | ····················checkMappingForField("", field, sortedFields, classMapping, false, fieldNode); |
680 | ············} |
681 | ········} |
682 | ············ |
683 | |
684 | ········private void |
685 | ········checkFieldMappings(ClassNode classNode, Class classMapping) |
686 | ········{ |
687 | ············ArrayList sortedFields = new ArrayList(); |
688 | ············string className = classNode.Name; |
689 | ············allSortedFields.Add(className, sortedFields); |
690 | |
691 | ············List<FieldNode> oidFields = new List<FieldNode>(); |
692 | |
693 | ············// All own fields |
694 | ············IList fieldList = classNode.Fields; |
695 | ············IterateFieldNodeList(fieldList, false, oidFields, classMapping, sortedFields, false); |
696 | |
697 | ············// All embedded objects |
698 | ············IList embeddedObjectsList = classNode.EmbeddedTypes; |
699 | ············IterateFieldNodeList(embeddedObjectsList, true, oidFields, classMapping, sortedFields, false); |
700 | |
701 | ············FieldSorter fieldSorter = new FieldSorter(); |
702 | ············sortedFields.Sort(fieldSorter); |
703 | |
704 | ············// Alle ererbten Felder |
705 | ············ClassNode derivedclassNode = this.allPersistentClasses[classNode.BaseName]; |
706 | ············ |
707 | ············while (null != derivedclassNode) |
708 | ············{ |
709 | ················if (derivedclassNode.IsPersistent) |
710 | ················{ |
711 | ····················int startind = sortedFields.Count; |
712 | |
713 | ····················IList nl = derivedclassNode.Fields; |
714 | ····················IterateFieldNodeList(nl, false, oidFields, classMapping, sortedFields, true); |
715 | ················ |
716 | ····················IList enl = derivedclassNode.EmbeddedTypes; |
717 | ····················IterateFieldNodeList(enl, true, oidFields, classMapping, sortedFields, true); |
718 | |
719 | ····················int len = sortedFields.Count - startind; |
720 | ····················sortedFields.Sort(startind, len, fieldSorter); |
721 | ················} |
722 | ················derivedclassNode = this.allPersistentClasses[derivedclassNode.BaseName]; |
723 | ············} |
724 | |
725 | ············// Ab hier nur noch Zeug für die Mapping-Datei |
726 | ············if (classMapping == null) |
727 | ················return; |
728 | |
729 | |
730 | ············if (oidFields.Count > 0) |
731 | ············{ |
732 | ················foreach (FieldNode oidField in oidFields) |
733 | ················{ |
734 | ····················OidColumn oidColumn = null; |
735 | ····················new OidColumnIterator(classMapping).Iterate(delegate(OidColumn oidCol, bool isLastElement) |
736 | ····················{ |
737 | ························if (oidCol.FieldName == oidField.Name) |
738 | ····························oidColumn = oidCol; |
739 | ····················}); |
740 | ····················if (oidColumn == null) |
741 | ····················{ |
742 | ························oidColumn = classMapping.Oid.NewOidColumn(); |
743 | ························oidColumn.FieldName = oidField.Name; |
744 | ························oidColumn.Name = classMapping.FindField(oidField.Name).Column.Name; |
745 | ····················} |
746 | ················} |
747 | ············} |
748 | |
749 | ············foreach(DictionaryEntry de in sortedFields) |
750 | ················sortedFieldsFile.WriteLine((string)de.Key); |
751 | ············sortedFieldsFile.WriteLine(); |
752 | |
753 | |
754 | ············// Und nun die überflüssigen entfernen |
755 | ············List<Field> fieldsToRemove = new List<Field>(); |
756 | ············foreach(Field f in classMapping.Fields) |
757 | ············{ |
758 | ················bool isExistent = false; |
759 | ················foreach(DictionaryEntry e in sortedFields) |
760 | ················{ |
761 | ····················if ((string)e.Key == f.Name) |
762 | ····················{ |
763 | ························isExistent = true; |
764 | ························break; |
765 | ····················} |
766 | ················} |
767 | ················if (!isExistent) |
768 | ····················fieldsToRemove.Add(f); |
769 | ············} |
770 | ············foreach(Field field in fieldsToRemove) |
771 | ················classMapping.RemoveField(field); |
772 | |
773 | ············List<Field> sortedFieldMappings = classMapping.Fields.ToList(); |
774 | ············sortedFieldMappings.Sort( ( f1, f2 ) => string.CompareOrdinal( ((Field)f1).Name, ((Field)f2).Name ) ); |
775 | ············for (int i = 0; i < sortedFieldMappings.Count; i++) |
776 | ················((Field)sortedFieldMappings[i]).Ordinal = i; |
777 | ········} |
778 | |
779 | |
780 | ········private void SetDefiningClass(Relation r, Class parent) |
781 | ········{ |
782 | ············Type t = typeof(Relation); |
783 | ············FieldInfo fi = t.GetField("definingClass", BindingFlags.NonPublic | BindingFlags.Instance); |
784 | ············fi.SetValue(r, parent); |
785 | ········} |
786 | |
787 | ········public void |
788 | ········checkInheritedRelationMappings(ClassNode classNode, Class classMapping) |
789 | ········{ |
790 | ············string className = classNode.Name; |
791 | |
792 | ············ReferenceArrayList references = (ReferenceArrayList) this.allReferences[className]; |
793 | ············// Alle ererbten Relationen |
794 | ············ClassNode baseClassNode = this.allPersistentClasses[classNode.BaseName]; |
795 | ············ |
796 | ············while (null != baseClassNode) |
797 | ············{ |
798 | ················if (baseClassNode.IsPersistent) |
799 | ················{ |
800 | ····················Class baseClassMapping = baseClassNode.Class; |
801 | ····················ArrayList temp = new ArrayList(); |
802 | ····················IList nl = baseClassNode.Relations; |
803 | ····················foreach (RelationNode relNode in nl) |
804 | ····················{ |
805 | ························// Relation nur aus der Klasse nehmen, die das Feld deklariert |
806 | ························if (relNode.DeclaringType != null) |
807 | ····························continue; |
808 | ························//····················string tn = relNode.Attributes["Type"].Value; |
809 | ························RelationInfo ri = relNode.RelationInfo; |
810 | ························string rname = relNode.Name; |
811 | ························ |
812 | ························// Die Relation sollte wirklich am unteren Ende der |
813 | ························// Klassenhierarchie erzeugt werden. |
814 | ························//····················if(references.Contains(rname)) |
815 | ························//····················Debug.Write("NDO635"); |
816 | ························Debug.Assert(!references.Contains(rname)); |
817 | ········································ |
818 | |
819 | ························// relation wird als ererbte Reference in die Liste eingetragen. |
820 | ························bool is1To1 = relNode.IsElement; |
821 | ························string relTypeName = relNode.RelatedType; |
822 | ························string relName = relNode.RelationName; |
823 | ························string ilType = relNode.DataType; |
824 | ························Type containerType = relNode.FieldType; |
825 | |
826 | ························ClassNode relClassNode = allPersistentClasses[relTypeName]; |
827 | ························if (relClassNode.AssemblyName != this.ownAssemblyName && !relTypeName.StartsWith("[")) |
828 | ····························relTypeName = "[" + relClassNode.AssemblyName + "]" + relTypeName; |
829 | ························//TODO: warnen wenn Oid-Typen nicht übereinstimmen |
830 | ························references.Add(new Patcher.ILReference(containerType, relTypeName, ilType, rname, this.ownAssemblyName, ri, relName, true, is1To1, "class " + className)); |
831 | |
832 | ························if (classMapping != null) |
833 | ························{ |
834 | ····························// Ist diese Relation schon definiert? Wenn ja, wird sie nicht geändert |
835 | ····························Relation r = classMapping.FindRelation(rname); |
836 | ····························if (null == r) |
837 | ····························{ |
838 | ································messages.WriteLine(String.Format("Ererbte Relation {0}.{1} wird kopiert", classNode.Name, rname)); |
839 | ································if (null == baseClassMapping) |
840 | ····································throw new Exception(String.Format("Kann die Mapping-Information für die Basisklasse {0} nicht finden", baseClassNode.Name)); |
841 | ································r = baseClassMapping.FindRelation(rname); |
842 | ································if (r == null) |
843 | ····································throw new Exception(String.Format("Schwerwiegender interner Fehler: Ererbte Relation {0} in Basisklasse {1} nicht gefunden.", rname, baseClassMapping.FullName));································ |
844 | ································classMapping.AddRelation(r); |
845 | ····························} |
846 | ····························else |
847 | ····························{ |
848 | ································Relation orgRel = baseClassMapping.FindRelation( rname ); |
849 | ································if (r.AccessorName == null && r.AccessorName != orgRel.AccessorName) |
850 | ····································r.AccessorName = orgRel.AccessorName; |
851 | ····························} |
852 | ····························if (is1To1) |
853 | ································r.Multiplicity = RelationMultiplicity.Element; |
854 | ····························else |
855 | ································r.Multiplicity = RelationMultiplicity.List; |
856 | ························} |
857 | ····················} |
858 | ················} |
859 | ················baseClassNode = this.allPersistentClasses[baseClassNode.BaseName]; |
860 | ············} |
861 | ········} |
862 | |
863 | ········public void |
864 | ········checkRelationMappings(ClassNode classNode, Class classMapping) |
865 | ········{ |
866 | ············IList references = new ReferenceArrayList(); |
867 | ············string className = (classNode.Name); |
868 | ············allReferences.Add(className, references); |
869 | ············IList refList = classNode.Relations; |
870 | ············foreach (RelationNode relationNode in refList) |
871 | ············{ |
872 | ················// Übernehme die Relation nur aus der deklarierenden Klasse, |
873 | ················// damit gleich die richtigen Mappings eingetragen werden. |
874 | ················if (relationNode.DeclaringType != null) |
875 | ····················continue; |
876 | ················string fieldName = relationNode.Name; |
877 | ················string relTypeName = relationNode.RelatedType; |
878 | ················bool is1To1 = relationNode.IsElement; |
879 | ················string relName = relationNode.RelationName; |
880 | ················RelationInfo ri = relationNode.RelationInfo; |
881 | ················string ilType = relationNode.DataType; |
882 | ················Type containerType = relationNode.FieldType; |
883 | |
884 | ················if (!classNode.IsInterface) |
885 | ················{ |
886 | ····················if (classMapping == null) |
887 | ························continue; |
888 | ····················Relation r = classMapping.FindRelation(fieldName); |
889 | ····················ClassNode relClassNode = allPersistentClasses[relTypeName]; |
890 | ····················if (null == r) |
891 | ····················{ |
892 | ························//TODO: ForeignKeyColumnAttributes... |
893 | ························string relTypeFullName = relTypeName.Substring(relTypeName.IndexOf("]") + 1);························ |
894 | ························if (relClassNode == null) |
895 | ····························throw new Exception(String.Format("Class '{1}' has a relation to a non persistent type '{0}'.", relTypeFullName, classNode.Name)); |
896 | ························messages.WriteLine("Creating standard relation " + classNode.Name + "." + fieldName); |
897 | ························r = classMapping.AddStandardRelation(fieldName, relTypeFullName, is1To1, relName, classNode.IsPoly, relClassNode.IsPoly || relClassNode.IsAbstract, relationNode.MappingTableAttribute); |
898 | ····················} |
899 | ····················else |
900 | ····················{ |
901 | ························r.RemapMappingTable( classNode.IsPoly, relClassNode.IsPoly || relClassNode.IsAbstract, relationNode.MappingTableAttribute ); |
902 | ························r.RemapForeignKeyColumns( relationNode.ForeignKeyColumnAttributes, relationNode.ChildForeignKeyColumnAttributes );··// currently nothing happens there. |
903 | ····················} |
904 | ····················SetDefiningClass(r, classMapping); |
905 | ····················if (is1To1) |
906 | ························r.Multiplicity = RelationMultiplicity.Element; |
907 | ····················else |
908 | ························r.Multiplicity = RelationMultiplicity.List; |
909 | ················} |
910 | ················references.Add(new Patcher.ILReference(containerType, relTypeName, ilType, fieldName, this.ownAssemblyName, ri, relName, false, is1To1, null)); |
911 | ············} |
912 | ········} |
913 | |
914 | |
915 | ········private void |
916 | ········checkClassMappings(ArrayList classList) |
917 | ········{ |
918 | ············if (options.DatabaseOwner != string.Empty) |
919 | ················mappings.StandardDbOwner = options.DatabaseOwner; |
920 | ············sortedFieldsFile = new StreamWriter(Path.ChangeExtension(binFile, ".fields.txt")); |
921 | ············foreach(ClassNode classNode in classList) |
922 | ············{ |
923 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
924 | ····················continue; |
925 | ················string assName = classNode.AssemblyName; |
926 | ················if (verboseMode) |
927 | ················{ |
928 | ····················if (assName != this.ownAssemblyName) |
929 | ························messages.WriteLine("Warning: Inconsistency: Class from foreign assembly: " + classNode.Name); |
930 | ················} |
931 | ················Class classMapping = null; |
932 | ················if (!classNode.IsInterface) |
933 | ················{ |
934 | ····················string className = classNode.Name; |
935 | ····················sortedFieldsFile.WriteLine(className + ":"); |
936 | ····················classMapping = mappings.FindClass(className); |
937 | ····················if (classMapping == null) |
938 | ····················{ |
939 | #if !STD |
940 | ························try |
941 | ························{ |
942 | #endif |
943 | ····························messages.WriteLine("Generating class mapping for class '" + className + "'"); |
944 | |
945 | ····························if (classNode.IsAbstract) |
946 | ································classMapping = mappings.AddAbstractClass(className, assName, classNode.ColumnAttributes); |
947 | ····························else |
948 | ································classMapping = mappings.AddStandardClass(className, assName, classNode.ColumnAttributes); |
949 | ························ |
950 | #if !STD |
951 | ························} |
952 | ························catch (ArgumentOutOfRangeException ex) |
953 | ························{ |
954 | ····························throw new Exception(Decryptor.Decrypt(NDOErrors.TooMuchClasses)); |
955 | ························} |
956 | #endif |
957 | ···························· |
958 | ····················} |
959 | ····················if (options.UseTimeStamps && (classMapping.TimeStampColumn == null || classMapping.TimeStampColumn == string.Empty)) |
960 | ························classMapping.TimeStampColumn = "NDOTimeStamp"; |
961 | ····················if (classNode.ClassType.IsGenericType && classMapping.TypeNameColumn == null) |
962 | ························classMapping.AddTypeNameColumn(); |
963 | ················} |
964 | ················checkFieldMappings(classNode, classMapping); |
965 | ············} |
966 | ············sortedFieldsFile.Close(); |
967 | |
968 | ············// Lösche ungebrauchte Class Mappings |
969 | ············ArrayList classesToDelete = new ArrayList(); |
970 | ············foreach(Class c in mappings.Classes) |
971 | ············{ |
972 | ················if (!tabuClasses.Contains(c.FullName) |
973 | ················&& allPersistentClasses[c.FullName] == null) |
974 | ························classesToDelete.Add(c); |
975 | ············} |
976 | ············foreach (Class c in classesToDelete) |
977 | ············{ |
978 | ················messages.WriteLine(String.Format("Deleting unused class mapping {0}", c.FullName)); |
979 | ················mappings.RemoveClass(c); |
980 | ············} |
981 | ········} |
982 | |
983 | ········private void checkAllRelationMappings(ArrayList classList) |
984 | ········{ |
985 | ············foreach(ClassNode classNode in classList) |
986 | ············{ |
987 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
988 | ····················continue; |
989 | ················Class classMapping = classNode.Class; |
990 | ················checkRelationMappings(classNode, classMapping); |
991 | ············} |
992 | |
993 | ············foreach(ClassNode classNode in classList) |
994 | ············{ |
995 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
996 | ····················continue; |
997 | ················Class classMapping = classNode.Class; |
998 | ················checkInheritedRelationMappings(classNode, classMapping); |
999 | ············} |
1000 | |
1001 | ············foreach(ClassNode classNode in classList) |
1002 | ············{ |
1003 | ················if (classNode.IsInterface) |
1004 | ····················continue; |
1005 | ················if (!classNode.IsPersistent) // non persistent classes derived from persistent classes |
1006 | ····················continue; |
1007 | ················Class classMapping = classNode.Class; |
1008 | ················if (classMapping == null) |
1009 | ····················continue; |
1010 | ················deleteUnusedRelationMappings(classMapping); |
1011 | ················checkDoubleComposites(classMapping); |
1012 | ············} |
1013 | ········} |
1014 | |
1015 | |
1016 | ········private void deleteUnusedRelationMappings(Class classMapping) |
1017 | ········{ |
1018 | ············ReferenceArrayList references = (ReferenceArrayList) this.allReferences[classMapping.FullName]; |
1019 | ············ArrayList relationsToDelete = new ArrayList(); |
1020 | ············foreach (Relation r in classMapping.Relations) |
1021 | ············{ |
1022 | ················if (!references.Contains(r.FieldName)) |
1023 | ····················relationsToDelete.Add(r); |
1024 | ············} |
1025 | ············foreach (Relation r in relationsToDelete) |
1026 | ············{ |
1027 | ················messages.WriteLine(String.Format("Delete unused Relation Mapping {0}", classMapping.FullName + "." + r.FieldName)); |
1028 | ················classMapping.RemoveRelation(r); |
1029 | ············} |
1030 | ········} |
1031 | |
1032 | ········private void checkDoubleComposites(Class classMapping) |
1033 | ········{ |
1034 | ············ReferenceArrayList references = (ReferenceArrayList) this.allReferences[classMapping.FullName]; |
1035 | ············foreach (Relation r in classMapping.Relations) |
1036 | ············{ |
1037 | ················Patcher.ILReference reference = references.FindReference(r.FieldName); |
1038 | ················if (reference != null) |
1039 | ················{ |
1040 | ····················Relation r2 = r.ForeignRelation; |
1041 | ····················if (r2 != null) |
1042 | ····················{ |
1043 | ························ReferenceArrayList references2 = (ReferenceArrayList) this.allReferences[r.ReferencedTypeName]; |
1044 | ························if(references2 == null)··// Type is not from our assembly |
1045 | ····························continue; |
1046 | ························Patcher.ILReference reference2 = references2.FindReference(r2.FieldName); |
1047 | ························if (reference2 != null) |
1048 | ························{ |
1049 | ····························if (reference.ReferenceInfo == RelationInfo.Composite |
1050 | ································&& reference2.ReferenceInfo == RelationInfo.Composite) |
1051 | ································throw new Exception(String.Format("Error: Bidirectional relation between class {0} and class {1} is a composite in both directions. Please remove the composite flag at one of the two classes.", classMapping.FullName, r.ReferencedTypeName)); |
1052 | ························} |
1053 | ····················} |
1054 | ················} |
1055 | ············} |
1056 | ········} |
1057 | |
1058 | |
1059 | ········public void |
1060 | ········mergeMappingFile(string absDllPath, ArrayList classList) |
1061 | ········{ |
1062 | ············var dir = Path.GetDirectoryName(absDllPath); |
1063 | ············var mapFileName = Path.Combine(dir, Path.GetFileNameWithoutExtension(absDllPath) + ".ndo.mapping"); |
1064 | ············if (!File.Exists( mapFileName )) |
1065 | ················mapFileName = Path.Combine(dir, "NDOMapping.xml"); |
1066 | |
1067 | ············if (classList.Count > 0 && !File.Exists(mapFileName)) |
1068 | ············{ |
1069 | ················messages.WriteLine("Mapping file for assembly " + absDllPath + " not found."); |
1070 | ················return; |
1071 | ············} |
1072 | |
1073 | ············NDOMapping mergeMapping; |
1074 | |
1075 | ············try |
1076 | ············{ |
1077 | ················mergeMapping = new NDOMapping(mapFileName); |
1078 | ············} |
1079 | ············catch (Exception ex) |
1080 | ············{ |
1081 | ················throw new Exception("Can't read mapping file " + mapFileName + ".\n"+ex.Message); |
1082 | ············} |
1083 | ············foreach(Class classMapping in mergeMapping.Classes) |
1084 | ················tabuClasses.Add(classMapping.FullName); |
1085 | |
1086 | ············mappings.MergeMapping(mergeMapping); |
1087 | |
1088 | ············foreach(ClassNode classNode in classList) |
1089 | ············{ |
1090 | ················Class cls; |
1091 | ················string className = classNode.Name; |
1092 | ················if (null == (cls = mappings.FindClass(className))) |
1093 | ················{ |
1094 | ····················messages.WriteLine("Mapping information for class " + className + " in file " + mapFileName + " not found."); |
1095 | ····················messages.WriteInsertedLine("Try to recompile the assembly " + absDllPath + "."); |
1096 | ················} |
1097 | ············} |
1098 | ········} |
1099 | |
1100 | ········private string CombinePath(string path, string file) |
1101 | ········{ |
1102 | ············string p = path; |
1103 | ············if (p.EndsWith("\\")) |
1104 | ················p = p.Substring(0, p.Length - 1); |
1105 | ············while (file.StartsWith(@"..\")) |
1106 | ············{ |
1107 | ················p = Path.GetDirectoryName(p); |
1108 | ················file = file.Substring(3); |
1109 | ············} |
1110 | ············return p + "\\" + file; |
1111 | ········} |
1112 | |
1113 | ········public void |
1114 | ············doIt() |
1115 | ········{ |
1116 | |
1117 | #if BETA || TRIAL |
1118 | ············expired = !NDOKey.CheckDate(new LicenceKey().TheKey, DateTime.Now); |
1119 | #endif |
1120 | ············bool sourcesUpToDate = !options.EnableEnhancer; |
1121 | #if BETA || TRIAL |
1122 | ············if (expired) |
1123 | ················throw new Exception("NDO Licence expired"); |
1124 | #endif |
1125 | #if DEBUG |
1126 | ············this.verboseMode = true; |
1127 | #else |
1128 | ············this.verboseMode = options.VerboseMode; |
1129 | #endif |
1130 | ············DateTime objTime = DateTime.MinValue; |
1131 | |
1132 | ············if (options.EnableEnhancer) |
1133 | ············{ |
1134 | ················DateTime enhTime; |
1135 | ················DateTime ilEnhTime; |
1136 | |
1137 | ················if (!File.Exists(objFile)) |
1138 | ················{ |
1139 | ····················messages.WriteLine("Enhancer: Kann Datei " + objFile + " nicht finden"); |
1140 | ····················return; |
1141 | ················} |
1142 | |
1143 | ················objTime = File.GetLastWriteTime(objFile); |
1144 | |
1145 | ················if (File.Exists(ilEnhFile) && File.Exists(enhFile)) |
1146 | ················{ |
1147 | ····················enhTime = File.GetLastWriteTime(enhFile); |
1148 | ····················ilEnhTime = File.GetLastWriteTime(ilEnhFile); |
1149 | |
1150 | ····················// objFile·· = obj\debug\xxx.dll |
1151 | ····················// ilEnhFile = obj\ndotemp\xxx.il |
1152 | ····················// enhFile·· = obj\ndotemp\xxx.dll |
1153 | ····················// binFile·· = bin\debug\xxx.dll |
1154 | ····················if (objTime < ilEnhTime && ilEnhTime <= enhTime) |
1155 | ····················{ |
1156 | ························// Sicherstellen, dass das Binary existiert |
1157 | ························File.Copy(enhFile, binFile, true); |
1158 | ························if (debug) |
1159 | ····························File.Copy(enhPdbFile, binPdbFile, true); |
1160 | |
1161 | ························sourcesUpToDate = true; |
1162 | ····················} |
1163 | ················} |
1164 | ············} |
1165 | ············// Mapping-Datei im Bin-Verzeichnis muss jünger oder gleich alt sein wie Mapping-Source-Datei |
1166 | ············if (sourcesUpToDate) |
1167 | ············{ |
1168 | ················if (File.Exists(mappingFile) && File.Exists(mappingDestFile)) |
1169 | ················{ |
1170 | ····················DateTime mapSourceTime = File.GetLastWriteTime(mappingFile); |
1171 | ····················DateTime mapDestTime = File.GetLastWriteTime(mappingDestFile); |
1172 | ····················sourcesUpToDate = mapDestTime >= mapSourceTime && mapDestTime >= objTime; |
1173 | ····················// Mapping-Datei muss jünger sein als die bin-Datei |
1174 | ····················if (!projectDescription.IsWebProject && !File.Exists(projectDescription.BinFile)) |
1175 | ························throw new Exception("Can't find binary " + projectDescription.BinFile); |
1176 | ····················DateTime binFileTime = File.GetLastWriteTime(projectDescription.BinFile); |
1177 | ····················if (binFileTime > mapSourceTime) |
1178 | ························sourcesUpToDate = false; |
1179 | ················} |
1180 | ················else |
1181 | ····················sourcesUpToDate = false; |
1182 | ············} |
1183 | |
1184 | ············// Schemadatei muss nach der letzten Kompilierung erzeugt worden sein |
1185 | #if DEBUG |
1186 | ············sourcesUpToDate = false; |
1187 | #endif |
1188 | ············if (sourcesUpToDate) |
1189 | ············{ |
1190 | ················if (File.Exists(schemaFile)) |
1191 | ················{ |
1192 | ····················if (File.GetLastWriteTime(schemaFile) >= objTime) |
1193 | ························return; |
1194 | ················} |
1195 | ············} |
1196 | ············ |
1197 | ············if (options.DefaultConnection != string.Empty) |
1198 | ············{ |
1199 | ················Connection.StandardConnection.Name = options.DefaultConnection; |
1200 | ················Connection.StandardConnection.Type = options.SQLScriptLanguage; |
1201 | ············} |
1202 | ············else |
1203 | ············{ |
1204 | ················Connection.StandardConnection.Name = Connection.DummyConnectionString; |
1205 | ············} |
1206 | |
1207 | ············string wrongDll = null; |
1208 | |
1209 | ············try |
1210 | ············{ |
1211 | ················if (options.NewMapping) |
1212 | ····················File.Delete(mappingFile); |
1213 | ················if (this.verboseMode) |
1214 | ····················messages.WriteLine("Mapping file is: " + mappingFile); |
1215 | |
1216 | #if !STD |
1217 | ················try |
1218 | ················{ |
1219 | #endif |
1220 | ····················mappings = new NDOMapping(mappingFile); |
1221 | ····················mappings.SchemaVersion = options.SchemaVersion; |
1222 | ····················((IEnhancerSupport)mappings).IsEnhancing = true; |
1223 | #if !STD |
1224 | ················} |
1225 | ················catch (ArgumentOutOfRangeException ex) |
1226 | ················{ |
1227 | ····················if (ex.Source == "System.Collections") |
1228 | ························throw new Exception("Too much elements for Community edition: max. 1 connection, 10 classes, 500 objects, 8 relations per class, 8 fields per class are allowed."); |
1229 | ····················else |
1230 | ························throw ex; |
1231 | ················} |
1232 | #endif |
1233 | //#if !STD |
1234 | //················Type t = mappings.Classes.GetType(); |
1235 | //················NDOAssemblyName an = new NDOAssemblyName(t.Assembly.FullName); |
1236 | //················if (an.Name != "System.Collections") |
1237 | //················{ |
1238 | //····················wrongDll = Decryptor.Decrypt(NDOErrors.WrongDll); |
1239 | //················} |
1240 | //#endif |
1241 | ············} |
1242 | #if !STD |
1243 | ············catch (ArgumentOutOfRangeException ex) |
1244 | ············{ |
1245 | ················throw new Exception(Decryptor.Decrypt(NDOErrors.TooMuchElements)); |
1246 | ············} |
1247 | #endif |
1248 | ············catch (Exception ex) |
1249 | ············{ |
1250 | ················if (null != ex.Message) |
1251 | ····················throw new Exception("Can't load Mapping File " + mappingFile + ".\n" + ex.ToString()); |
1252 | ················else |
1253 | ····················throw new Exception("Can't load Mapping File " + mappingFile); |
1254 | ············} |
1255 | |
1256 | ············if (wrongDll != null) |
1257 | ················throw new Exception(wrongDll); |
1258 | |
1259 | ············dsSchema = new NDODataSet(); |
1260 | ············dsSchema.EnforceConstraints = false; |
1261 | |
1262 | ············// The mapping und schema files |
1263 | ············// will be merged here |
1264 | ············searchPersistentBases(); |
1265 | ············bool doEnhance = options.EnableEnhancer && !this.isEnhanced; |
1266 | #if xDEBUG |
1267 | ············doEnhance = options.EnableEnhancer; |
1268 | #endif |
1269 | ············if (this.verboseMode) |
1270 | ············{ |
1271 | ················messages.WriteLine(options.EnableEnhancer ? "Enhancer enabled" : "Enhancer disabled"); |
1272 | ················if (doEnhance) |
1273 | ····················messages.WriteLine(this.isEnhanced ? "Assembly is already enhanced" : "Assembly is not yet enhanced"); |
1274 | ················else |
1275 | ····················messages.WriteLine("Assembly won't be enhanced"); |
1276 | ············} |
1277 | ············if (doEnhance) |
1278 | ············{ |
1279 | ················// Hier wird ILDasm bemüht, um einen Dump des Assemblies herzustellen |
1280 | ················disassemble(); |
1281 | |
1282 | ················ILFile ilfile = new ILFile(); |
1283 | |
1284 | ················messages.WriteLine( "Enhancing Assembly" ); |
1285 | ················messages.Indent(); |
1286 | |
1287 | ················// Hier wird der Elementbaum erzeugt |
1288 | ················ilfile.parse( ilFileName ); |
1289 | ················ILAssemblyElement.Iterator assit = ilfile.getAssemblyIterator(); |
1290 | ················ILAssemblyElement el; |
1291 | ················if (projectDescription.KeyFile == string.Empty) |
1292 | ····················this.assemblyKeyFile = null; |
1293 | ················else |
1294 | ····················this.assemblyKeyFile = projectDescription.KeyFile; |
1295 | ················for (el = assit.getNext(); el != null; el = assit.getNext() ) |
1296 | ················{ |
1297 | ····················if (!el.isExtern()) |
1298 | ····················{ |
1299 | ························ILCustomElement.Iterator cusit = el.getCustomIterator(); |
1300 | ························ILCustomElement custEl; |
1301 | ························for (custEl = cusit.getNext(); custEl != null; custEl = cusit.getNext()) |
1302 | ························{ |
1303 | ····························ILCustomElement.AttributeInfo ai = custEl.getAttributeInfo(); |
1304 | ····························if (ai.Name == "System.Reflection.AssemblyKeyAttribute") |
1305 | ····························{ |
1306 | ································string s = (string) ai.ParamValues[0]; |
1307 | ································if (s != null && s != string.Empty) |
1308 | ································{ |
1309 | ····································this.assemblyKeyFile = ("@" + s); |
1310 | ····································break; |
1311 | ································} |
1312 | ····························} |
1313 | ····························if (ai.Name == "System.Reflection.AssemblyKeyFileAttribute") |
1314 | ····························{ |
1315 | ································string s = (string) ai.ParamValues[0]; |
1316 | ································if (s != null && s != string.Empty) |
1317 | ································{ |
1318 | ····································string fn; |
1319 | ····································if (s.IndexOf(@":\") == -1) |
1320 | ········································fn = CombinePath(this.objPath, s); |
1321 | ····································else |
1322 | ········································fn = s; |
1323 | ····································if (File.Exists(fn)) |
1324 | ········································this.assemblyKeyFile = fn; |
1325 | ····································break; |
1326 | ································} |
1327 | ····························} |
1328 | ························} |
1329 | ························if (this.assemblyKeyFile != null) |
1330 | ····························break; |
1331 | ····················} |
1332 | ················} |
1333 | |
1334 | ················//mergeValueTypes(ilfile); |
1335 | |
1336 | ················analyzeAndEnhance(ilfile); |
1337 | |
1338 | ················messages.Unindent(); |
1339 | ················if (this.verboseMode) |
1340 | ····················messages.WriteLine( "Generating Binary" ); |
1341 | ···················· |
1342 | ················// Hier wird der enhanced Elementbaum als IL-Datei geschrieben |
1343 | ················ilfile.write( ilEnhFile, Corlib.FxType == FxType.Standard2 ); |
1344 | |
1345 | ················// ILAsm assembliert das Ganze |
1346 | ················reassemble(); |
1347 | ············} |
1348 | |
1349 | |
1350 | ············// Store the mapping information |
1351 | ············if (this.verboseMode) |
1352 | ················messages.WriteLine( "Saving mapping file" ); |
1353 | ············mappings.Save(); |
1354 | ············if (verboseMode) |
1355 | ················Console.WriteLine("Copying mapping file to '" + mappingDestFile + "'"); |
1356 | ············File.Copy(mappingFile, mappingDestFile, true); |
1357 | |
1358 | ············if (this.verboseMode) |
1359 | ················messages.WriteLine( "Generating schema file" ); |
1360 | ············if (File.Exists(schemaFile)) |
1361 | ················File.Copy(schemaFile, schemaFile.Replace(".ndo.xsd", ".ndo.xsd.bak"), true); |
1362 | ············dsSchema.WriteXmlSchema(schemaFile); |
1363 | |
1364 | ············if (options.GenerateSQL) |
1365 | ············{ |
1366 | ················if (this.verboseMode) |
1367 | ····················messages.WriteLine( "Generating sql file" ); |
1368 | ················string sqlFileName = schemaFile.Replace(".xsd", ".sql"); |
1369 | ················TypeManager tm = null; |
1370 | ················if (options.IncludeTypecodes) |
1371 | ················{ |
1372 | ····················string typeFile = Path.Combine(Path.GetDirectoryName(binFile), "NDOTypes.Xml"); |
1373 | ····················tm = new TypeManager(typeFile, this.mappings); |
1374 | ················} |
1375 | ················string oldSchemaFile = schemaFile.Replace(".ndo.xsd", ".ndo.xsd.bak"); |
1376 | ················NDODataSet dsOld = null; |
1377 | ················if (File.Exists(oldSchemaFile)) |
1378 | ················{ |
1379 | ····················dsOld = new NDODataSet(oldSchemaFile); |
1380 | ····················new SQLDiffGenerator().Generate(options.SQLScriptLanguage, options.Utf8Encoding, dsSchema, dsOld, sqlFileName, mappings, messages); |
1381 | ····················new NdoTransDiffGenerator().Generate(dsSchema, dsOld, sqlFileName, mappings, messages); |
1382 | ················} |
1383 | ················else |
1384 | ················{ |
1385 | ····················new NdoTransDiffGenerator().Generate( dsSchema, new DataSet(), sqlFileName, mappings, messages ); |
1386 | ················} |
1387 | ················if (!this.options.DropExistingElements) |
1388 | ····················dsOld = null;··// causes, that no drop statements will be generated. |
1389 | ················new SQLGenerator().Generate(options.SQLScriptLanguage, options.Utf8Encoding, dsSchema, dsOld, sqlFileName, mappings, messages, tm, this.options.GenerateConstraints); |
1390 | ············} |
1391 | |
1392 | ········} |
1393 | |
1394 | ········void analyzeAndEnhance( ILFile ilFile ) |
1395 | ········{············ |
1396 | ············IList classes = ilFile.getAllClassElements(); |
1397 | |
1398 | ············if (!isEnhanced) |
1399 | ············{ |
1400 | ················IList foreignAssemblies = checkRelationTargetAssemblies(); |
1401 | |
1402 | ················ILAssemblyElement.Iterator ai = ilFile.getAssemblyIterator(); |
1403 | ················bool insertData = true; |
1404 | ················bool insertXml = true; |
1405 | ················bool insertNdo = true; |
1406 | ················bool insertNdoInterfaces = true; |
1407 | ················bool insertSystem = true; |
1408 | |
1409 | ················for ( ILAssemblyElement assElem = ai.getNext(); null != assElem; assElem = ai.getNext() ) |
1410 | ················{ |
1411 | ····················string nameLower = assElem.getName().ToLower(); |
1412 | ····················if (foreignAssemblies.Contains(assElem.getName())) |
1413 | ························foreignAssemblies.Remove(assElem.getName()); |
1414 | ····················string line = assElem.getLine(0); |
1415 | ····················if (!assElem.isExtern()) |
1416 | ····················{ |
1417 | ························ILElement lastEl = assElem.getCustomIterator().getLast(); |
1418 | ························lastEl.insertBefore(new ILCustomElement(".custom instance void [NDO]NDO.NDOEnhancedAttribute::.ctor() = ( 01 00 00 00 )", assElem)); |
1419 | ····················} |
1420 | ····················if (line.StartsWith(".assembly")) |
1421 | ····················{ |
1422 | ························if (nameLower == "system.data") |
1423 | ····························insertData = false; |
1424 | ························if (nameLower == "system.xml") |
1425 | ····························insertXml = false; |
1426 | ························if (nameLower == "system") |
1427 | ····························insertSystem = false; |
1428 | ························if (nameLower == "ndo") |
1429 | ························{ |
1430 | ····························if (this.verboseMode) |
1431 | ····························{ |
1432 | ································messages.WriteLine("NDO Dll:"); |
1433 | ································ILElementIterator it = assElem.getAllIterator(true); |
1434 | ································for (ILElement subEl = it.getFirst(); subEl != null; subEl = it.getNext()) |
1435 | ····································messages.WriteInsertedLine(subEl.getAllLines()); |
1436 | ····························} |
1437 | ····························insertNdo = false; |
1438 | |
1439 | ····························/* We don't need a version check anymore. This might be necessary again, if it comes to .NET Version 5 |
1440 | ····························if (assElem.Major != 2 && assElem.Minor != 0) |
1441 | ····························{ |
1442 | ································string version = EnhDate.String; |
1443 | ································Regex regex = new Regex( @"V\. (\d+\.\d+)" ); |
1444 | ································Match match = regex.Match( version ); |
1445 | ································if (match.Success) |
1446 | ····································version = match.Groups[1].Value; |
1447 | ································throw new Exception("This assembly is built with NDO.dll Version " + assElem.VersionString.Replace(':', '.') |
1448 | ····································+ ". This NDO enhancer only works with NDO.dll version " + version + ". Please correct your assembly reference and rebuild the assembly."); |
1449 | ····························} |
1450 | ····························*/ |
1451 | #if NDO12 |
1452 | ····························if (assElem.Major != 1 && assElem.Minor != 2) |
1453 | ····························{ |
1454 | ································throw new Exception("This assembly is built with NDO.dll Version " + assElem.VersionString.Replace(':', '.') |
1455 | ····································+ ". This NDO enhancer only works with NDO.dll version 1.2. Please correct your assembly reference and rebuild the assembly."); |
1456 | ····························} |
1457 | #endif |
1458 | #if NDO11 |
1459 | ····························if (assElem.Major != 1 && assElem.Minor != 1) |
1460 | ····························{ |
1461 | ································throw new Exception("This assembly is built with NDO.dll Version " + assElem.VersionString.Replace(':', '.') |
1462 | ····································+ ". This NDO enhancer only works with NDO.dll version 1.1. Please correct your assembly reference and rebuild the assembly."); |
1463 | ····························}······················ |
1464 | #endif |
1465 | ························} |
1466 | ························if (nameLower == "ndointerfaces") |
1467 | ························{ |
1468 | ····························insertNdoInterfaces = false; |
1469 | #if NDO12 |
1470 | ····························if (assElem.Major != 1 && assElem.Minor != 2) |
1471 | ····························{ |
1472 | ································throw new Exception("This assembly is built with NDOInterfaces.dll Version " + assElem.VersionString.Replace(':', '.') |
1473 | ····································+ ". This NDO enhancer only works with NDOInterfaces.dll version > 1.2. Please correct your assembly reference and rebuild the assembly."); |
1474 | ····························} |
1475 | #endif |
1476 | #if NDO11 |
1477 | ····························if (assElem.Major != 1 && assElem.Minor != 1) |
1478 | ····························{ |
1479 | ································throw new Exception("This assembly is built with NDOInterfaces.dll Version " + assElem.VersionString.Replace(':', '.') |
1480 | ····································+ ". This NDO enhancer only works with NDOInterfaces.dll version 1.1. Please correct your assembly reference and rebuild the assembly."); |
1481 | ····························}······················ |
1482 | #endif |
1483 | ························} |
1484 | ····················} |
1485 | #if DEBUG |
1486 | ····················else |
1487 | ····················{ |
1488 | ························throw new Exception("Assembly element doesn't start with .assembly."); |
1489 | ····················} |
1490 | #endif |
1491 | ················} |
1492 | |
1493 | ················ai = ilFile.getAssemblyIterator(); |
1494 | ················ILAssemblyElement ael = ai.getNext(); |
1495 | ················//················string verString; |
1496 | |
1497 | |
1498 | ················if (insertData) |
1499 | ················{ |
1500 | #if NET20 |
1501 | ····················string line = @".assembly extern System.Data |
1502 | { |
1503 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1504 | .ver 2:0:0:0 |
1505 | } |
1506 | "; |
1507 | #else |
1508 | ····················string line = @".assembly extern System.Data |
1509 | { |
1510 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1511 | .ver 1:0:3300:0 |
1512 | } |
1513 | "; |
1514 | #endif |
1515 | ····················ael.insertBefore(new ILElement(line)); |
1516 | ················} |
1517 | |
1518 | ················if (insertSystem) |
1519 | ················{ |
1520 | #if NET20 |
1521 | ····················string line = @".assembly extern System |
1522 | { |
1523 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1524 | .ver 2:0:0:0 |
1525 | } |
1526 | "; |
1527 | #else |
1528 | ····················string line = @".assembly extern System |
1529 | { |
1530 | ··.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1531 | ··.ver 1:0:5000:0 |
1532 | } |
1533 | "; |
1534 | #endif |
1535 | ····················ael.insertBefore(new ILElement(line)); |
1536 | ················} |
1537 | |
1538 | ················if (insertXml) |
1539 | ················{ |
1540 | //····················Assembly ass = Assembly.GetAssembly(typeof(System.Data.DataRow)); |
1541 | //····················verString = getAssemblyInfo(ass, "Version=", ""); |
1542 | //····················verString = ".ver " + verString.Replace(".", ":"); |
1543 | #if NET20 |
1544 | ····················string line = @".assembly extern System.Xml |
1545 | { |
1546 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1547 | .ver 2:0:0:0 |
1548 | } |
1549 | "; |
1550 | #else |
1551 | ····················string line = @".assembly extern System.Xml |
1552 | { |
1553 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) |
1554 | .ver 1:0:3300:0 |
1555 | } |
1556 | "; |
1557 | #endif |
1558 | ····················ael.insertBefore(new ILElement(line)); |
1559 | ················} |
1560 | |
1561 | ················if (insertNdo) |
1562 | ················{ |
1563 | ····················string fullName = typeof(NDOPersistentAttribute).Assembly.FullName; |
1564 | ····················NDOAssemblyName assName = new NDOAssemblyName(fullName); |
1565 | ····················messages.WriteLine("Inserting reference to NDO assembly: " + fullName); |
1566 | ····················string line = @".assembly extern NDO |
1567 | { |
1568 | .publickeytoken = (" + assName.PublicKeyTokenBytes + @") |
1569 | .ver " + assName.Version.Replace(".", ":") + @" |
1570 | } |
1571 | "; |
1572 | |
1573 | ····················ael.insertBefore(new ILElement(line)); |
1574 | ················} |
1575 | |
1576 | ················if (insertNdoInterfaces) |
1577 | ················{ |
1578 | ····················NDOAssemblyName assName = new NDOAssemblyName(typeof(NDOException).Assembly.FullName); |
1579 | ····················string line = @".assembly extern NDOInterfaces |
1580 | { |
1581 | .publickeytoken = (" + assName.PublicKeyTokenBytes + @") |
1582 | .ver " + assName.Version.Replace(".", ":") + @" |
1583 | } |
1584 | "; |
1585 | |
1586 | ····················ael.insertBefore(new ILElement(line)); |
1587 | ················} |
1588 | |
1589 | ················foreach(string s in foreignAssemblies) |
1590 | ················{ |
1591 | ····················string fullName = (string) assemblyFullNames[s]; |
1592 | ····················if (fullName == null) |
1593 | ····················{ |
1594 | ························messages.WriteLine("*** Can't find assembly with name '" + s + "' to be inserted as an assembly reference."); |
1595 | ························continue; |
1596 | ····················} |
1597 | ····················else |
1598 | ····················{ |
1599 | ························if (verboseMode) |
1600 | ····························messages.WriteLine("Insert reference to assembly " + fullName); |
1601 | ····················} |
1602 | |
1603 | ····················NDOAssemblyName assName = new NDOAssemblyName(fullName); |
1604 | ····················string publicKeyToken = string.Empty; |
1605 | ····················if (assName.PublicKeyToken != "null") |
1606 | ························publicKeyToken = ".publickeytoken = (" + assName.PublicKeyTokenBytes + ")\n"; |
1607 | ····················string line = @".assembly extern " + assName.Name + @" |
1608 | { |
1609 | " + publicKeyToken + @" |
1610 | .ver " + assName.Version.Replace(".", ":") + @" |
1611 | } |
1612 | "; |
1613 | |
1614 | ····················ael.insertBefore(new ILElement(line)); |
1615 | ···················· |
1616 | ················} |
1617 | |
1618 | ············} // !enhanced············ |
1619 | |
1620 | ············// Jetzt alle Klassen durchlaufen und ggf. Enhancen |
1621 | ············foreach ( ILClassElement classElement in··classes ) |
1622 | ············{ |
1623 | ················if (classElement.isPersistent(typeof (NDOPersistentAttribute))) |
1624 | ················{ |
1625 | ····················Dictionary<string, string> accessors = classElement.findAccessorProperties(); |
1626 | ····················Class classMapping = mappings.FindClass( classElement.getMappingName() ); |
1627 | ····················if (classMapping != null && accessors.Count > 0) |
1628 | ····················{ |
1629 | ························foreach (var item in accessors) |
1630 | ························{ |
1631 | ····························Field field = classMapping.FindField( item.Key ); |
1632 | ····························if (field != null) |
1633 | ····························{ |
1634 | ································field.AccessorName = item.Value; |
1635 | ····························} |
1636 | ····························else |
1637 | ····························{ |
1638 | ································Relation rel = classMapping.FindRelation( item.Key ); |
1639 | ································if (rel != null) |
1640 | ····································rel.AccessorName = item.Value; |
1641 | ····························} |
1642 | ························} |
1643 | ····················} |
1644 | ····················string mappingName = classElement.getMappingName(); |
1645 | ····················IList sortedFields = (IList) allSortedFields[mappingName]; |
1646 | ····················IList references = (IList) allReferences[mappingName]; |
1647 | ····················Patcher.ClassPatcher cls = new Patcher.ClassPatcher( classElement, mappings, allPersistentClasses, messages, sortedFields, references, this.oidTypeName ); |
1648 | ····················if (!isEnhanced) |
1649 | ····················{ |
1650 | ························// Klasse enhancen |
1651 | ························cls.enhance(); |
1652 | ····················} |
1653 | ················} |
1654 | ············}············ |
1655 | ········} |
1656 | |
1657 | |
1658 | |
1659 | |
1660 | ········private void |
1661 | ········disassemble() |
1662 | ········{ |
1663 | ············Dasm dasm = new Dasm(messages, this.verboseMode); |
1664 | ············dasm.DoIt(objFile, ilFileName); |
1665 | ············if (File.Exists(resFile)) |
1666 | ············{ |
1667 | ················File.Copy(resFile, resEnhFile, true); |
1668 | ················File.Delete(resFile); |
1669 | ············} |
1670 | ········} |
1671 | |
1672 | ········private void |
1673 | ········reassemble() |
1674 | ········{ |
1675 | ············Asm asm = new Asm(messages, this.verboseMode); |
1676 | ············if (this.verboseMode) |
1677 | ················messages.WriteLine("KeyFile: " + this.assemblyKeyFile); |
1678 | |
1679 | ············asm.DoIt(ilEnhFile, enhFile, this.assemblyKeyFile, debug); |
1680 | ············if (! File.Exists(enhFile)) |
1681 | ····················throw new Exception("Codeerzeugung: temporäre Datei " + enhFile + " konnte nicht erstellt werden."); |
1682 | ············string resFile = Path.ChangeExtension(enhFile, ".res"); |
1683 | ············if (File.Exists(resFile)) |
1684 | ················File.Delete(resFile); |
1685 | //············File.Copy( enhFile, binFile, true ); |
1686 | |
1687 | ············DateTime ct = File.GetCreationTime(objFile); |
1688 | ············DateTime at = File.GetLastAccessTime(objFile); |
1689 | ············DateTime wt = File.GetLastWriteTime(objFile); |
1690 | ············ |
1691 | //············File.Copy( enhFile, objFile, true ); |
1692 | |
1693 | ············File.SetCreationTime(enhFile, ct); |
1694 | ············File.SetLastAccessTime(enhFile, at); |
1695 | ············File.SetLastWriteTime(enhFile, wt); |
1696 | |
1697 | //············if ( debug ) |
1698 | //············{ |
1699 | //················if (! File.Exists(enhPdbFile)) |
1700 | //····················throw new Exception("Codeerzeugung: temporäre Datei " + enhPdbFile + " konnte nicht erstellt werden."); |
1701 | //················File.Copy( enhPdbFile, binPdbFile, true ); |
1702 | //············} |
1703 | |
1704 | ········} |
1705 | |
1706 | ····} |
1707 | } |
1708 |