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