Datei: NDODLL/PersistenceManagerBase.cs

Last Commit (98730da)
1 //
2 // Copyright (c) 2002-2016 Mirko Matytschak
3 // (www.netdataobjects.de)
4 //
5 // Author: Mirko Matytschak
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8 // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10 // Software, and to permit persons to whom the Software is furnished to do so, subject to the following
11 // conditions:
12
13 // The above copyright notice and this permission notice shall be included in all copies or substantial portions
14 // of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21
22
23 using System;
24 using System.Collections.Generic;
25 using System.Linq;
26 using System.IO;
27 using System.Data;
28 using NDO.Logging;
29 using NDO.Mapping;
30 using NDO.Configuration;
31 using NDO.SqlPersistenceHandling;
32 using System.Reflection;
33
34 namespace NDO
35 {
36 ····/// <summary>
37 ····/// Provides base functionality for PersistenceManager classes
38 ····/// </summary>
39 ····public class PersistenceManagerBase : IPersistenceManagerBase
40 ····{
41 ········internal Cache cache = new Cache();
42 ········/// <summary>
43 ········/// The DataSet used as template for DataRows
44 ········/// </summary>
45 ········protected DataSet ds = null;
46 ········/// <summary>
47 ········/// The StateManager instance which will be used for all objects
48 ········/// </summary>
49 ········protected IStateManager sm;
50 ········internal Mappings mappings;··// protected will make the compiler complaining
51 ········private string logPath;
52 ········private ILogAdapter logAdapter;
53 ········private Type persistenceHandlerType = null;
54 ········private INDOContainer configContainer;
55 ········private IPersistenceHandlerManager persistenceHandlerManager;
56 ········bool isClosing = false;
57
58 ········/// <summary>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59 ········/// Register a listener to this event, if you have to provide user generated ids.
60 ········/// This event is usefull for databases, which doesn't provide auto-incremented ids, like the Oracle Db.
61 ········/// The event will be fired if a new id is needed.
62 ········/// </summary>
63 ········public event IdGenerationHandler IdGenerationEvent;
64
65 ········/// <summary>
66 ········/// Constructor
67 ········/// </summary>
68 ········public PersistenceManagerBase()
69 ········{
70 ············string baseDir = AppDomain.CurrentDomain.BaseDirectory;
71 ············if (File.Exists( Path.Combine( baseDir, "Web.config" ) ))
72 ················baseDir = Path.Combine( baseDir, "bin" );
73 ············var entryAssemblyName = Assembly.GetEntryAssembly()?.GetName()?.Name;
74 ············List<string> paths = new List<string>();
75 ············if (entryAssemblyName != null)
76 ············paths.Add( Path.Combine( baseDir, $"{entryAssemblyName}.ndo.mapping" ) );
77 ············paths.Add( Path.Combine( baseDir, "NDOMapping.xml" ) );
78 ············
79 ············bool found = false;
80 ············foreach (var path in paths)
81 ············{
82 ················if (File.Exists(path))
83 ················{
84 ····················Init( path );
85 ····················found = true;
86 ····················break;
87 ················}
88 ············}
89 ············if (!found)
90 ················throw new NDOException( 49, $"Can't determine the path to the mapping file. Tried the following locations:\n{string.Join("\n", paths)}\nPlease provide a mapping file path as argument to the PersistenceManager ctor." );
91 ········}
92
93 ········/// <summary>
94 ········/// Constructs a PersistenceManagerBase object using the path to a mapping file.
95 ········/// </summary>
96 ········/// <param name="mappingFile"></param>
97 ········public PersistenceManagerBase(string mappingFile)
98 ········{
99 ············Init(mappingFile);
100 ········}
101
102 ········/// <summary>
103 ········/// Constructs a PersistenceManagerBase object using the mapping object.
104 ········/// </summary>
105 ········/// <param name="mapping"></param>
106 ········public PersistenceManagerBase(NDOMapping mapping)
107 ········{
108 ············var localMappings = mapping as Mappings;
109 ············if (localMappings == null)
110 ················throw new ArgumentException( "The mapping must be constructed by a PersistenceManager", nameof( mapping ) );
111
112 ············Init( localMappings );
113 ········}
114
115 ········/// <summary>
116 ········/// Initializes a PersistenceManager using the path to a mapping file
117 ········/// </summary>
118 ········/// <param name="mappingPath"></param>
119 ········protected virtual void Init(string mappingPath)
120 ········{
121 ············if (!File.Exists(mappingPath))
122 ················throw new NDOException(45, String.Format("Mapping File {0} doesn't exist.", mappingPath));
123 ············Init( new Mappings( mappingPath ) );
124 ········}
125
126 ········/// <summary>
127 ········/// Initializes the persistence manager
128 ········/// </summary>
129 ········/// <remarks>
130 ········/// Note: This is the method, which will be called from all different ways to instantiate a PersistenceManagerBase.
131 ········/// </remarks>
132 ········/// <param name="mapping"></param>
133 ········internal virtual void Init( Mappings mapping )
134 ········{
135 ············this.mappings = mapping;
136
137 ············ConfigContainer.RegisterInstance( mappings );
138
139 ············this.ds = new NDODataSet( mappings );··// Each PersistenceManager instance must have it's own DataSet.
140
141 ············string logPath = AppDomain.CurrentDomain.BaseDirectory;
142
143 ············if (logPath == null)
144 ················logPath = Path.GetDirectoryName( mapping.FileName );
145
146 ············this.LogPath = logPath;
147 ········}
148
149 ········/// <summary>
150 ········/// Used by PersistenceManagers, to get an owner supplied id.
151 ········/// </summary>
152 ········/// <param name="t">Type of the object, the id is intended for.</param>
153 ········/// <param name="oid">ObjectId object which will hold the id value.</param>
154 ········protected void FireIdGenerationEvent(Type t, ObjectId oid)
155 ········{
156 ············if (IdGenerationEvent != null)
157 ················IdGenerationEvent(t, oid);
158 ········}
159
160
161 ········Dictionary<string,Class> myClassesName;
162 ········Dictionary<Type, Class> myClassesType;
163
164 ········/// <summary>
165 ········/// Initializes the class mappings
166 ········/// </summary>
167 ········protected void InitClasses()
168 ········{
169 ············int cnt = mappings.Classes.Count();
170 ············myClassesName = new Dictionary<string, Class>(cnt);
171 ············myClassesType = new Dictionary<Type, Class>(cnt);
172 ············foreach(Class cl in mappings.Classes)
173 ············{
174 ················myClassesName.Add(cl.FullName, cl);
175 ················myClassesType.Add(cl.SystemType, cl);
176 ············}
177 ········}
178 ········
179
180 ········internal Class GetClass(string name)
181 ········{
182 ············if (!myClassesName.ContainsKey(name))
183 ················throw new NDOException(17, "Can't find mapping information for class " + name);
184
185 ············return myClassesName[name];
186 ········}
187
188 ········internal Class GetClass(IPersistenceCapable pc)
189 ········{
190 ············return GetClass(pc.GetType());
191 ········}
192
193 ········internal Class GetClass(Type type)
194 ········{
195 ············Type t = type;
196
197 ············if (type.IsGenericType)
198 ················t = type.GetGenericTypeDefinition();
199
200 ············if (! myClassesType.ContainsKey(t))
201 ················throw new NDOException(17, "Can't find mapping information for class " + t.FullName);
202
203 ············return myClassesType[t];
204
205 ········}
206
207 ········internal Field GetField(Class cl, string field)
208 ········{
209 ············Field f = cl.FindField(field);
210 ············if (f == null)
211 ················throw new NDOException(7, "Can't find mapping information for field " + cl.FullName + "." + field);
212 ············return f;
213 ········}
214
215 ········/// <summary>
216 ········/// Hilfsfunktion
217 ········/// Liefert die Tabelle im DataSet ab, in der die DataRows des Datentyps liegen
218 ········/// </summary>
219 ········/// <param name="t">Data type</param>
220 ········/// <returns></returns>
221 ········protected DataTable GetTable(Type t)
222 ········{
223 ············return GetTable(GetClass(t).TableName);
224 ········}
225
226 ········/// <summary>
227 ········/// Hilfsfunktion
228 ········/// Liefert die Tabelle im DataSet ab, in der die DataRow des Objekts liegt
229 ········/// </summary>
230 ········/// <param name="pc"></param>
231 ········/// <returns></returns>
232 ········protected DataTable GetTable(IPersistenceCapable pc)
233 ········{
234 ············return GetTable(GetClass(pc).TableName);
235 ········}
236
237
238 ········/// <summary>
239 ········/// Retrieve a table with the given name
240 ········/// </summary>
241 ········/// <param name="name">Table name</param>
242 ········/// <returns></returns>
243 ········protected DataTable GetTable(string name)
244 ········{
245 ············DataTable dt = ds.Tables[name];
246 ············if (dt == null)
247 ················throw new NDOException(39, "Can't find table '" + name + "' in the schema. Check your mapping file.");
248 ············return dt;
249 ········}
250
251 ········/// <summary>
252 ········/// Gets a DataRow for a given object; if necessary the row will be constructed
253 ········/// </summary>
254 ········/// <param name="pc">Persistence capable object</param>
255 ········/// <returns></returns>
256 ········protected DataRow GetDataRow(IPersistenceCapable pc)
257 ········{
258 ············DataRow row;
259 ············if ((row = this.cache.GetDataRow(pc)) != null)
260 ················return row;
261 ············return null;
262 ········}
263
264
265
266 ········/// <summary>
267 ········/// Indicates, if there is a listener registered for the IdGenerationEvent.
268 ········/// </summary>
269 ········public bool HasOwnerCreatedIds
270 ········{
271 ············get { return IdGenerationEvent != null; }
272 ········}
273
274 ········/// <summary>
275 ········/// If set, the PersistenceManager writes a log of all SQL statements issued to the databases.
276 ········/// By default a LogFileAdapter to the file SqlIOLog.txt will be used. The log medium can be
277 ········/// changed using the <see cref="NDO.PersistenceManagerBase.LogAdapter">LogAdapter property</see>.
278 ········/// </summary>
279 ········public virtual bool VerboseMode
280 ········{
281 ············get {return mappings.VerboseMode;}
282 ············set {mappings.VerboseMode = value;}
283 ········}
284
285 ········/// <summary>
286 ········/// Gets or sets the type which is used to construct persistence handlers.
287 ········/// </summary>
288 ········[Obsolete("Use the ConfigContainer to register a handler type.")]
289 ········public Type PersistenceHandlerType
290 ········{
291 ············get { return persistenceHandlerType; }
292 ············set
293 ············{
294 ················if (value != null && value.GetInterface("IPersistenceHandler") == null)
295 ····················throw new NDOException(46, "Invalid PersistenceHandlerType: " + value.FullName);
296 ················ConfigContainer.RegisterType( typeof( IPersistenceHandler ), persistenceHandlerType );
297 ············}
298 ········}
299
300 ········/// <summary>
301 ········/// Gets or sets the container for the configuration of the system.
302 ········/// </summary>
303 ········public INDOContainer ConfigContainer
304 ········{
305 ············get
306 ············{
307 ················if (this.configContainer == null)
308 ················{
309 ····················this.configContainer = NDOContainer.Instance.CreateChildContainer();
310 ····················this.configContainer.RegisterType<IQueryGenerator, SqlQueryGenerator>();
311
312 ····················// Currently the PersistenceManager instance is not used.
313 ····················// But we are able to pull it from the container.
314 ····················this.configContainer.RegisterInstance( typeof( PersistenceManager ), this );
315 ················}
316
317 ················return this.configContainer;
318 ············}
319 ············set { this.configContainer = value; }
320 ········}
321
322
323 ········/// <summary>
324 ········/// Sets or gets the logging Adapter, log information is written to.
325 ········/// </summary>
326 ········/// <remarks>
327 ········/// If LogPath is set, a LogFileAdapter object is created and attached to this property.
328 ········/// <seealso cref="LogPath"/><seealso cref="ILogAdapter"/>
329 ········/// </remarks>
330 ········public ILogAdapter LogAdapter
331 ········{
332 ············get
333 ············{
334 ················return this.logAdapter;
335 ············}
336 ············set
337 ············{
338 ················this.logAdapter = value;
339 ················mappings.LogAdapter = this.logAdapter;
340 ················LogFileAdapter lfa = this.logAdapter as LogFileAdapter;
341 ················if (lfa != null)
342 ················{
343 ····················this.logPath = Path.GetDirectoryName(lfa.FileName);
344 ················}
345 ············}
346 ········}
347
348 ········/// <summary>
349 ········/// Gets or sets an implementation of the PersistenceHandlerManager.
350 ········/// </summary>
351 ········public IPersistenceHandlerManager PersistenceHandlerManager
352 ········{
353 ············get
354 ············{
355 ················// (this.persistenceHandlerManager == null)
356 ················return this.persistenceHandlerManager = ConfigContainer.Resolve<IPersistenceHandlerManager>();
357
358 ················//return this.persistenceHandlerManager;
359 ············}
360 ············set { this.persistenceHandlerManager = value; }
361 ········}
362
363
364 ········/// <summary>
365 ········/// Gets or sets the directory, where NDO writes the sql log file to.
366 ········/// </summary>
367 ········/// <remarks>
368 ········/// A file with the name NDO.Sql.log will be generated in the LogPath, if
369 ········/// verbose mode is set to true. Note, that a FileLogAdapter object is created,
370 ········/// if LogPath is set. If a LogAdapter is set, LogPath might
371 ········/// reflect an undefined state.<seealso cref="LogAdapter"/><seealso cref="ILogAdapter"/>
372 ········/// </remarks>
373 ········public string LogPath
374 ········{
375 ············get { return logPath; }
376 ············set
377 ············{
378 ················logPath = value;
379 ················if (logPath == null)
380 ····················return;
381 ················if (!Directory.Exists(value))
382 ····················throw new NDOException(47, "Log path doesn't exist: " + value);
383 ················string fileName = Path.Combine(logPath, "NDO.Sql.log");
384 ················// use the Property to invoke the additional logic
385 ················this.LogAdapter = new LogFileAdapter(fileName);
386 ············}
387 ········}
388
389 ········
390 ········/// <summary>
391 ········/// Gets the Mapping structure of the application as stored in NDOMapping.xml.
392 ········/// Use it only if you know exactly, what you're doing!
393 ········/// Do not change anything in the mapping structure because it will cause the
394 ········/// NDO Framework to fail.
395 ········/// </summary>
396 ········public NDOMapping NDOMapping
397 ········{
398 ············get { return this.mappings; }
399 ········}
400
401 ········/// <summary>
402 ········/// Gets the DataSet behind the operations of the pm.
403 ········/// </summary>
404 ········/// <remarks>This property should't be used by user code. It exists only for test purposes.</remarks>
405 ········public DataSet DataSet
406 ········{
407 ············get { return this.ds; }
408 ········}
409
410 ········internal NDO.Cache Cache
411 ········{
412 ············get { return this.cache; }
413 ········}
414
415 ········/// <summary>
416 ········/// Clears any log file entries in the log file
417 ········/// </summary>
418 ········/// <remarks>
419 ········/// Note, that not all LogAdapters support this function. In that case, the
420 ········/// call to ClearLogfile is ignored.
421 ········/// </remarks>
422 ········public void ClearLogfile()
423 ········{
424 ············if (this.logAdapter != null)
425 ················this.LogAdapter.Clear();
426 ········}
427
428 ········/// <summary>
429 ········/// Determines, if a log message will actually be issued.
430 ········/// </summary>
431 ········public bool LoggingPossible
432 ········{
433 ············get { return (VerboseMode && this.logAdapter != null); }
434 ········}
435
436 ········/// <summary>
437 ········/// Checks whether an object is an IPersistenceCapable and converts the object into an IPersistenceCapable.
438 ········/// </summary>
439 ········/// <param name="o"></param>
440 ········/// <returns></returns>
441 ········/// <remarks>Throws an NDOException, if the object can't be converted.</remarks>
442 ········protected internal IPersistenceCapable CheckPc(object o)
443 ········{
444 ············IPersistenceCapable pc = o as IPersistenceCapable;
445 ············if (pc == null && !(o == null))
446 ················throw new NDOException(31, "Parameter should implement IPersistenceCapable. Check, if the type " + o.GetType().FullName + "," + o.GetType().Assembly.FullName + " is enhanced.");
447 ············return pc;
448 ········}
449
450 ········/// <summary>
451 ········/// Closes the PersistenceManager and releases all resources.
452 ········/// </summary>
453 ········public virtual void Close()
454 ········{
455 ············if (isClosing)
456 ················return;
457 ············isClosing = true;
458 ············this.ds.Dispose();
459 ············this.ds = null;
460 ············this.configContainer.Dispose();··// Leads to another Disposal of the PM. therefore we query for isClosing.
 
461 ········}
462
463 ········/// <summary>
464 ········/// IDisposable implementation.
465 ········/// </summary>
466 ········/// <remarks>Note: The derived classes don't need to override the Dispose methods, since Close() is virtual. Just override Close() and call base.Close() in the overridden version.</remarks>
467 ········/// <param name="disposing"></param>
468 ········protected virtual void Dispose(bool disposing)
469 ········{
470 ············if (disposing)
471 ················Close();
472 ········}
473
474 ········/// <summary>
475 ········/// Disposes any Resources which might be held by the PersistenceManager implementation.
476 ········/// </summary>
477 ········public virtual void Dispose()
478 ········{
479 ············Dispose( true );
480 ············GC.SuppressFinalize( this );
481 ········}
482
483 ········/// <summary>
484 ········/// Finalizer.
485 ········/// </summary>
486 ········~PersistenceManagerBase()
487 ········{
488 ············Dispose( false );
489 ········}
490 ····}
491 }
492
New Commit (7586755)
1 //
2 // Copyright (c) 2002-2016 Mirko Matytschak
3 // (www.netdataobjects.de)
4 //
5 // Author: Mirko Matytschak
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8 // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
10 // Software, and to permit persons to whom the Software is furnished to do so, subject to the following
11 // conditions:
12
13 // The above copyright notice and this permission notice shall be included in all copies or substantial portions
14 // of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19 // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21
22
23 using System;
24 using System.Collections.Generic;
25 using System.Linq;
26 using System.IO;
27 using System.Data;
28 using NDO.Logging;
29 using NDO.Mapping;
30 using NDO.Configuration;
31 using NDO.SqlPersistenceHandling;
32 using System.Reflection;
33
34 namespace NDO
35 {
36 ····/// <summary>
37 ····/// Provides base functionality for PersistenceManager classes
38 ····/// </summary>
39 ····public class PersistenceManagerBase : IPersistenceManagerBase
40 ····{
41 ········internal Cache cache = new Cache();
42 ········/// <summary>
43 ········/// The DataSet used as template for DataRows
44 ········/// </summary>
45 ········protected DataSet ds = null;
46 ········/// <summary>
47 ········/// The StateManager instance which will be used for all objects
48 ········/// </summary>
49 ········protected IStateManager sm;
50 ········internal Mappings mappings;··// protected will make the compiler complaining
51 ········private string logPath;
52 ········private ILogAdapter logAdapter;
53 ········private Type persistenceHandlerType = null;
54 ········private INDOContainer configContainer;
55 ········private IPersistenceHandlerManager persistenceHandlerManager;
56 ········bool isClosing = false;
57
58 ········/// <summary>
59 ········/// If set to true, the resultset of each query is stored, so that results of an identical query
60 ········/// can be read from the cache.
61 ········/// </summary>
62 ········/// <remarks>
63 ········/// NDO computes an SHA256 hash for each query including the query parameters. The hash is the key to the query cache.
64 ········/// Do not use the QueryCache in applications, which work with one PersistenceManager
65 ········/// over a long time with multiple transactions.
66 ········/// </remarks>
67 ········public bool UseQueryCache { get; set; }
68
69 ········private Dictionary<string, object> queryCache = new Dictionary<string, object>();
70
71 ········/// <summary>
72 ········/// This is the query cache in which resultsets can be stored.
73 ········/// </summary>
74 ········/// <remarks>Usually you won't have to access the query cache.</remarks>
75 ········public Dictionary<string, object> QueryCache => this.queryCache;
76
77 ········/// <summary>
78 ········/// Register a listener to this event, if you have to provide user generated ids.
79 ········/// This event is usefull for databases, which doesn't provide auto-incremented ids, like the Oracle Db.
80 ········/// The event will be fired if a new id is needed.
81 ········/// </summary>
82 ········public event IdGenerationHandler IdGenerationEvent;
83
84 ········/// <summary>
85 ········/// Constructor
86 ········/// </summary>
87 ········public PersistenceManagerBase()
88 ········{
89 ············string baseDir = AppDomain.CurrentDomain.BaseDirectory;
90 ············if (File.Exists( Path.Combine( baseDir, "Web.config" ) ))
91 ················baseDir = Path.Combine( baseDir, "bin" );
92 ············var entryAssemblyName = Assembly.GetEntryAssembly()?.GetName()?.Name;
93 ············List<string> paths = new List<string>();
94 ············if (entryAssemblyName != null)
95 ············paths.Add( Path.Combine( baseDir, $"{entryAssemblyName}.ndo.mapping" ) );
96 ············paths.Add( Path.Combine( baseDir, "NDOMapping.xml" ) );
97 ············
98 ············bool found = false;
99 ············foreach (var path in paths)
100 ············{
101 ················if (File.Exists(path))
102 ················{
103 ····················Init( path );
104 ····················found = true;
105 ····················break;
106 ················}
107 ············}
108 ············if (!found)
109 ················throw new NDOException( 49, $"Can't determine the path to the mapping file. Tried the following locations:\n{string.Join("\n", paths)}\nPlease provide a mapping file path as argument to the PersistenceManager ctor." );
110 ········}
111
112 ········/// <summary>
113 ········/// Constructs a PersistenceManagerBase object using the path to a mapping file.
114 ········/// </summary>
115 ········/// <param name="mappingFile"></param>
116 ········public PersistenceManagerBase(string mappingFile)
117 ········{
118 ············Init(mappingFile);
119 ········}
120
121 ········/// <summary>
122 ········/// Constructs a PersistenceManagerBase object using the mapping object.
123 ········/// </summary>
124 ········/// <param name="mapping"></param>
125 ········public PersistenceManagerBase(NDOMapping mapping)
126 ········{
127 ············var localMappings = mapping as Mappings;
128 ············if (localMappings == null)
129 ················throw new ArgumentException( "The mapping must be constructed by a PersistenceManager", nameof( mapping ) );
130
131 ············Init( localMappings );
132 ········}
133
134 ········/// <summary>
135 ········/// Initializes a PersistenceManager using the path to a mapping file
136 ········/// </summary>
137 ········/// <param name="mappingPath"></param>
138 ········protected virtual void Init(string mappingPath)
139 ········{
140 ············if (!File.Exists(mappingPath))
141 ················throw new NDOException(45, String.Format("Mapping File {0} doesn't exist.", mappingPath));
142 ············Init( new Mappings( mappingPath ) );
143 ········}
144
145 ········/// <summary>
146 ········/// Initializes the persistence manager
147 ········/// </summary>
148 ········/// <remarks>
149 ········/// Note: This is the method, which will be called from all different ways to instantiate a PersistenceManagerBase.
150 ········/// </remarks>
151 ········/// <param name="mapping"></param>
152 ········internal virtual void Init( Mappings mapping )
153 ········{
154 ············this.mappings = mapping;
155
156 ············ConfigContainer.RegisterInstance( mappings );
157
158 ············this.ds = new NDODataSet( mappings );··// Each PersistenceManager instance must have it's own DataSet.
159
160 ············string logPath = AppDomain.CurrentDomain.BaseDirectory;
161
162 ············if (logPath == null)
163 ················logPath = Path.GetDirectoryName( mapping.FileName );
164
165 ············this.LogPath = logPath;
166 ········}
167
168 ········/// <summary>
169 ········/// Used by PersistenceManagers, to get an owner supplied id.
170 ········/// </summary>
171 ········/// <param name="t">Type of the object, the id is intended for.</param>
172 ········/// <param name="oid">ObjectId object which will hold the id value.</param>
173 ········protected void FireIdGenerationEvent(Type t, ObjectId oid)
174 ········{
175 ············if (IdGenerationEvent != null)
176 ················IdGenerationEvent(t, oid);
177 ········}
178
179
180 ········Dictionary<string,Class> myClassesName;
181 ········Dictionary<Type, Class> myClassesType;
182
183 ········/// <summary>
184 ········/// Initializes the class mappings
185 ········/// </summary>
186 ········protected void InitClasses()
187 ········{
188 ············int cnt = mappings.Classes.Count();
189 ············myClassesName = new Dictionary<string, Class>(cnt);
190 ············myClassesType = new Dictionary<Type, Class>(cnt);
191 ············foreach(Class cl in mappings.Classes)
192 ············{
193 ················myClassesName.Add(cl.FullName, cl);
194 ················myClassesType.Add(cl.SystemType, cl);
195 ············}
196 ········}
197 ········
198
199 ········internal Class GetClass(string name)
200 ········{
201 ············if (!myClassesName.ContainsKey(name))
202 ················throw new NDOException(17, "Can't find mapping information for class " + name);
203
204 ············return myClassesName[name];
205 ········}
206
207 ········internal Class GetClass(IPersistenceCapable pc)
208 ········{
209 ············return GetClass(pc.GetType());
210 ········}
211
212 ········internal Class GetClass(Type type)
213 ········{
214 ············Type t = type;
215
216 ············if (type.IsGenericType)
217 ················t = type.GetGenericTypeDefinition();
218
219 ············if (! myClassesType.ContainsKey(t))
220 ················throw new NDOException(17, "Can't find mapping information for class " + t.FullName);
221
222 ············return myClassesType[t];
223
224 ········}
225
226 ········internal Field GetField(Class cl, string field)
227 ········{
228 ············Field f = cl.FindField(field);
229 ············if (f == null)
230 ················throw new NDOException(7, "Can't find mapping information for field " + cl.FullName + "." + field);
231 ············return f;
232 ········}
233
234 ········/// <summary>
235 ········/// Hilfsfunktion
236 ········/// Liefert die Tabelle im DataSet ab, in der die DataRows des Datentyps liegen
237 ········/// </summary>
238 ········/// <param name="t">Data type</param>
239 ········/// <returns></returns>
240 ········protected DataTable GetTable(Type t)
241 ········{
242 ············return GetTable(GetClass(t).TableName);
243 ········}
244
245 ········/// <summary>
246 ········/// Hilfsfunktion
247 ········/// Liefert die Tabelle im DataSet ab, in der die DataRow des Objekts liegt
248 ········/// </summary>
249 ········/// <param name="pc"></param>
250 ········/// <returns></returns>
251 ········protected DataTable GetTable(IPersistenceCapable pc)
252 ········{
253 ············return GetTable(GetClass(pc).TableName);
254 ········}
255
256
257 ········/// <summary>
258 ········/// Retrieve a table with the given name
259 ········/// </summary>
260 ········/// <param name="name">Table name</param>
261 ········/// <returns></returns>
262 ········protected DataTable GetTable(string name)
263 ········{
264 ············DataTable dt = ds.Tables[name];
265 ············if (dt == null)
266 ················throw new NDOException(39, "Can't find table '" + name + "' in the schema. Check your mapping file.");
267 ············return dt;
268 ········}
269
270 ········/// <summary>
271 ········/// Gets a DataRow for a given object; if necessary the row will be constructed
272 ········/// </summary>
273 ········/// <param name="pc">Persistence capable object</param>
274 ········/// <returns></returns>
275 ········protected DataRow GetDataRow(IPersistenceCapable pc)
276 ········{
277 ············DataRow row;
278 ············if ((row = this.cache.GetDataRow(pc)) != null)
279 ················return row;
280 ············return null;
281 ········}
282
283
284
285 ········/// <summary>
286 ········/// Indicates, if there is a listener registered for the IdGenerationEvent.
287 ········/// </summary>
288 ········public bool HasOwnerCreatedIds
289 ········{
290 ············get { return IdGenerationEvent != null; }
291 ········}
292
293 ········/// <summary>
294 ········/// If set, the PersistenceManager writes a log of all SQL statements issued to the databases.
295 ········/// By default a LogFileAdapter to the file SqlIOLog.txt will be used. The log medium can be
296 ········/// changed using the <see cref="NDO.PersistenceManagerBase.LogAdapter">LogAdapter property</see>.
297 ········/// </summary>
298 ········public virtual bool VerboseMode
299 ········{
300 ············get {return mappings.VerboseMode;}
301 ············set {mappings.VerboseMode = value;}
302 ········}
303
304 ········/// <summary>
305 ········/// Gets or sets the type which is used to construct persistence handlers.
306 ········/// </summary>
307 ········[Obsolete("Use the ConfigContainer to register a handler type.")]
308 ········public Type PersistenceHandlerType
309 ········{
310 ············get { return persistenceHandlerType; }
311 ············set
312 ············{
313 ················if (value != null && value.GetInterface("IPersistenceHandler") == null)
314 ····················throw new NDOException(46, "Invalid PersistenceHandlerType: " + value.FullName);
315 ················ConfigContainer.RegisterType( typeof( IPersistenceHandler ), persistenceHandlerType );
316 ············}
317 ········}
318
319 ········/// <summary>
320 ········/// Gets or sets the container for the configuration of the system.
321 ········/// </summary>
322 ········public INDOContainer ConfigContainer
323 ········{
324 ············get
325 ············{
326 ················if (this.configContainer == null)
327 ················{
328 ····················this.configContainer = NDOContainer.Instance.CreateChildContainer();
329 ····················this.configContainer.RegisterType<IQueryGenerator, SqlQueryGenerator>();
330
331 ····················// Currently the PersistenceManager instance is not used.
332 ····················// But we are able to pull it from the container.
333 ····················this.configContainer.RegisterInstance( typeof( PersistenceManager ), this );
334 ················}
335
336 ················return this.configContainer;
337 ············}
338 ············set { this.configContainer = value; }
339 ········}
340
341
342 ········/// <summary>
343 ········/// Sets or gets the logging Adapter, log information is written to.
344 ········/// </summary>
345 ········/// <remarks>
346 ········/// If LogPath is set, a LogFileAdapter object is created and attached to this property.
347 ········/// <seealso cref="LogPath"/><seealso cref="ILogAdapter"/>
348 ········/// </remarks>
349 ········public ILogAdapter LogAdapter
350 ········{
351 ············get
352 ············{
353 ················return this.logAdapter;
354 ············}
355 ············set
356 ············{
357 ················this.logAdapter = value;
358 ················mappings.LogAdapter = this.logAdapter;
359 ················LogFileAdapter lfa = this.logAdapter as LogFileAdapter;
360 ················if (lfa != null)
361 ················{
362 ····················this.logPath = Path.GetDirectoryName(lfa.FileName);
363 ················}
364 ············}
365 ········}
366
367 ········/// <summary>
368 ········/// Gets or sets an implementation of the PersistenceHandlerManager.
369 ········/// </summary>
370 ········public IPersistenceHandlerManager PersistenceHandlerManager
371 ········{
372 ············get
373 ············{
374 ················// (this.persistenceHandlerManager == null)
375 ················return this.persistenceHandlerManager = ConfigContainer.Resolve<IPersistenceHandlerManager>();
376
377 ················//return this.persistenceHandlerManager;
378 ············}
379 ············set { this.persistenceHandlerManager = value; }
380 ········}
381
382
383 ········/// <summary>
384 ········/// Gets or sets the directory, where NDO writes the sql log file to.
385 ········/// </summary>
386 ········/// <remarks>
387 ········/// A file with the name NDO.Sql.log will be generated in the LogPath, if
388 ········/// verbose mode is set to true. Note, that a FileLogAdapter object is created,
389 ········/// if LogPath is set. If a LogAdapter is set, LogPath might
390 ········/// reflect an undefined state.<seealso cref="LogAdapter"/><seealso cref="ILogAdapter"/>
391 ········/// </remarks>
392 ········public string LogPath
393 ········{
394 ············get { return logPath; }
395 ············set
396 ············{
397 ················logPath = value;
398 ················if (logPath == null)
399 ····················return;
400 ················if (!Directory.Exists(value))
401 ····················throw new NDOException(47, "Log path doesn't exist: " + value);
402 ················string fileName = Path.Combine(logPath, "NDO.Sql.log");
403 ················// use the Property to invoke the additional logic
404 ················this.LogAdapter = new LogFileAdapter(fileName);
405 ············}
406 ········}
407
408 ········
409 ········/// <summary>
410 ········/// Gets the Mapping structure of the application as stored in NDOMapping.xml.
411 ········/// Use it only if you know exactly, what you're doing!
412 ········/// Do not change anything in the mapping structure because it will cause the
413 ········/// NDO Framework to fail.
414 ········/// </summary>
415 ········public NDOMapping NDOMapping
416 ········{
417 ············get { return this.mappings; }
418 ········}
419
420 ········/// <summary>
421 ········/// Gets the DataSet behind the operations of the pm.
422 ········/// </summary>
423 ········/// <remarks>This property should't be used by user code. It exists only for test purposes.</remarks>
424 ········public DataSet DataSet
425 ········{
426 ············get { return this.ds; }
427 ········}
428
429 ········internal NDO.Cache Cache
430 ········{
431 ············get { return this.cache; }
432 ········}
433
434 ········/// <summary>
435 ········/// Clears any log file entries in the log file
436 ········/// </summary>
437 ········/// <remarks>
438 ········/// Note, that not all LogAdapters support this function. In that case, the
439 ········/// call to ClearLogfile is ignored.
440 ········/// </remarks>
441 ········public void ClearLogfile()
442 ········{
443 ············if (this.logAdapter != null)
444 ················this.LogAdapter.Clear();
445 ········}
446
447 ········/// <summary>
448 ········/// Determines, if a log message will actually be issued.
449 ········/// </summary>
450 ········public bool LoggingPossible
451 ········{
452 ············get { return (VerboseMode && this.logAdapter != null); }
453 ········}
454
455 ········/// <summary>
456 ········/// Checks whether an object is an IPersistenceCapable and converts the object into an IPersistenceCapable.
457 ········/// </summary>
458 ········/// <param name="o"></param>
459 ········/// <returns></returns>
460 ········/// <remarks>Throws an NDOException, if the object can't be converted.</remarks>
461 ········protected internal IPersistenceCapable CheckPc(object o)
462 ········{
463 ············IPersistenceCapable pc = o as IPersistenceCapable;
464 ············if (pc == null && !(o == null))
465 ················throw new NDOException(31, "Parameter should implement IPersistenceCapable. Check, if the type " + o.GetType().FullName + "," + o.GetType().Assembly.FullName + " is enhanced.");
466 ············return pc;
467 ········}
468
469 ········/// <summary>
470 ········/// Closes the PersistenceManager and releases all resources.
471 ········/// </summary>
472 ········public virtual void Close()
473 ········{
474 ············if (isClosing)
475 ················return;
476 ············isClosing = true;
477 ············this.ds.Dispose();
478 ············this.ds = null;
479 ············this.configContainer.Dispose();··// Leads to another Disposal of the PM. therefore we query for isClosing.
480 ············this.queryCache.Clear();
481 ········}
482
483 ········/// <summary>
484 ········/// IDisposable implementation.
485 ········/// </summary>
486 ········/// <remarks>Note: The derived classes don't need to override the Dispose methods, since Close() is virtual. Just override Close() and call base.Close() in the overridden version.</remarks>
487 ········/// <param name="disposing"></param>
488 ········protected virtual void Dispose(bool disposing)
489 ········{
490 ············if (disposing)
491 ················Close();
492 ········}
493
494 ········/// <summary>
495 ········/// Disposes any Resources which might be held by the PersistenceManager implementation.
496 ········/// </summary>
497 ········public virtual void Dispose()
498 ········{
499 ············Dispose( true );
500 ············GC.SuppressFinalize( this );
501 ········}
502
503 ········/// <summary>
504 ········/// Finalizer.
505 ········/// </summary>
506 ········~PersistenceManagerBase()
507 ········{
508 ············Dispose( false );
509 ········}
510 ····}
511 }
512