Datei: NDOEnhancer/NDOEnhancer/Enhancer/Enhancer.cs

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