1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Collections.ObjectModel;
5 using System.Data.Linq;
6 using System.Linq.Expressions;
7 using System.Reflection;
8 using System.Text;
9 using System.Linq;
10 using System.Diagnostics.CodeAnalysis;
11 
12 namespace System.Data.Linq.Mapping {
13     /// <summary>
14     /// A MetaModel is an abstraction representing the mapping between a database and domain objects
15     /// </summary>
16     public abstract class MetaModel {
17         /// <summary>
18         ///  The mapping source that originated this model.
19         /// </summary>
20         public abstract MappingSource MappingSource { get; }
21         /// <summary>
22         /// The type of DataContext type this model describes.
23         /// </summary>
24         public abstract Type ContextType { get; }
25         /// <summary>
26         /// The name of the database.
27         /// </summary>
28         public abstract string DatabaseName { get; }
29         /// <summary>
30         /// The CLR type that implements IProvider to use as a provider.
31         /// </summary>
32         public abstract Type ProviderType { get; }
33         /// <summary>
34         /// Gets the MetaTable associated with a given type.
35         /// </summary>
36         /// <param name="rowType">The CLR row type.</param>
37         /// <returns>The MetaTable if one exists, otherwise null.</returns>
GetTable(Type rowType)38         public abstract MetaTable GetTable(Type rowType);
39         /// <summary>
40         /// Gets the MetaFunction corresponding to a database function: user-defined function, table-valued function or stored-procedure.
41         /// </summary>
42         /// <param name="method">The method defined on the DataContext or subordinate class that represents the database function.</param>
43         /// <returns>The MetaFunction if one exists, otherwise null.</returns>
GetFunction(MethodInfo method)44         public abstract MetaFunction GetFunction(MethodInfo method);
45         /// <summary>
46         /// Get an enumeration of all tables.
47         /// </summary>
48         /// <returns>An enumeration of all the MetaTables</returns>
49         [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Non-trivial operations are not suitable for properties.")]
GetTables()50         public abstract IEnumerable<MetaTable> GetTables();
51         /// <summary>
52         /// Get an enumeration of all functions.
53         /// </summary>
54         /// <returns>An enumeration of all the MetaFunctions</returns>
55         [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Non-trivial operations are not suitable for properties.")]
GetFunctions()56         public abstract IEnumerable<MetaFunction> GetFunctions();
57         /// <summary>
58         /// This method discovers the MetaType for the given Type.
59         /// </summary>
GetMetaType(Type type)60         public abstract MetaType GetMetaType(Type type);
61         /// <summary>
62         /// Internal value used to determine a reference identity for comparing meta models
63         /// without needing to keep track of the actual meta model reference.
64         /// </summary>
65         private object identity = new object();
66         internal object Identity {
67             get { return this.identity; }
68         }
69     }
70 
71     /// <summary>
72     /// A MetaTable represents an abstraction of a database table (or view)
73     /// </summary>
74     public abstract class MetaTable {
75         /// <summary>
76         /// The MetaModel containing this MetaTable.
77         /// </summary>
78         public abstract MetaModel Model { get; }
79         /// <summary>
80         /// The name of the table as defined by the database.
81         /// </summary>
82         public abstract string TableName { get; }
83         /// <summary>
84         /// The MetaType describing the type of the rows of the table.
85         /// </summary>
86         public abstract MetaType RowType { get; }
87         /// <summary>
88         /// The DataContext method used to perform insert operations
89         /// </summary>
90         public abstract MethodInfo InsertMethod { get; }
91         /// <summary>
92         /// The DataContext method used to perform update operations
93         /// </summary>
94         public abstract MethodInfo UpdateMethod { get; }
95         /// <summary>
96         /// The DataContext method used to perform delete operations
97         /// </summary>
98         public abstract MethodInfo DeleteMethod { get; }
99     }
100 
101     /// <summary>
102     /// A MetaType represents the mapping of a domain object type onto a database table's columns.
103     /// </summary>
104     public abstract class MetaType {
105         /// <summary>
106         /// The MetaModel containing this MetaType.
107         /// </summary>
108         public abstract MetaModel Model { get; }
109         /// <summary>
110         /// The MetaTable using this MetaType for row definition.
111         /// </summary>
112         public abstract MetaTable Table { get; }
113         /// <summary>
114         /// The underlying CLR type.
115         /// </summary>
116         [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The contexts in which this is available are fairly specific.")]
117         public abstract Type Type { get; }
118         /// <summary>
119         /// The name of the MetaType (same as the CLR type's name).
120         /// </summary>
121         public abstract string Name { get; }
122         /// <summary>
123         /// True if the MetaType is an entity type.
124         /// </summary>
125         public abstract bool IsEntity { get; }
126         /// <summary>
127         /// True if the underlying type can be instantiated as the result of a query.
128         /// </summary>
129         public abstract bool CanInstantiate { get; }
130         /// <summary>
131         /// The member that represents the auto-generated identity column, or null if there is none.
132         /// </summary>
133         public abstract MetaDataMember DBGeneratedIdentityMember { get; }
134         /// <summary>
135         /// The member that represents the row-version or timestamp column, or null if there is none.
136         /// </summary>
137         public abstract MetaDataMember VersionMember { get; }
138         /// <summary>
139         /// The member that represents the inheritance discriminator column, or null if there is none.
140         /// </summary>
141         public abstract MetaDataMember Discriminator { get; }
142         /// <summary>
143         /// True if the type has any persistent member with an UpdateCheck policy other than Never.
144         /// </summary>
145         public abstract bool HasUpdateCheck { get; }
146         /// <summary>
147         /// True if the type is part of a mapped inheritance hierarchy.
148         /// </summary>
149         public abstract bool HasInheritance { get; }
150         /// <summary>
151         /// True if this type defines an inheritance code.
152         /// </summary>
153         public abstract bool HasInheritanceCode { get; }
154         /// <summary>
155         /// The inheritance code defined by this type.
156         /// </summary>
157         public abstract object InheritanceCode { get; }
158         /// <summary>
159         /// True if this type is used as the default of an inheritance hierarchy.
160         /// </summary>
161         public abstract bool IsInheritanceDefault { get; }
162         /// <summary>
163         /// The root type of the inheritance hierarchy.
164         /// </summary>
165         public abstract MetaType InheritanceRoot { get; }
166         /// <summary>
167         /// The base metatype in the inheritance hierarchy.
168         /// </summary>
169         public abstract MetaType InheritanceBase { get; }
170         /// <summary>
171         /// The type that is the default of the inheritance hierarchy.
172         /// </summary>
173         public abstract MetaType InheritanceDefault { get; }
174         /// <summary>
175         /// Gets the MetaType for an inheritance sub type.
176         /// </summary>
177         /// <param name="type">The root or sub type of the inheritance hierarchy.</param>
178         /// <returns>The MetaType.</returns>
GetInheritanceType(Type type)179         public abstract MetaType GetInheritanceType(Type type);
180         /// <summary>
181         /// Gets type associated with the specified inheritance code.
182         /// </summary>
183         /// <param name="code">The inheritance code</param>
184         /// <returns>The MetaType.</returns>
GetTypeForInheritanceCode(object code)185         public abstract MetaType GetTypeForInheritanceCode(object code);
186         /// <summary>
187         /// Gets an enumeration of all types defined by an inheritance hierarchy.
188         /// </summary>
189         /// <returns>Enumeration of MetaTypes.</returns>
190         public abstract ReadOnlyCollection<MetaType> InheritanceTypes { get; }
191         /// <summary>
192         /// Returns true if the MetaType or any base MetaType has an OnLoaded method.
193         /// </summary>
194         public abstract bool HasAnyLoadMethod { get; }
195         /// <summary>
196         /// Returns true if the MetaType or any base MetaType has an OnValidate method.
197         /// </summary>
198         public abstract bool HasAnyValidateMethod { get; }
199         /// <summary>
200         /// Gets an enumeration of the immediate derived types in an inheritance hierarchy.
201         /// </summary>
202         /// <returns>Enumeration of MetaTypes.</returns>
203         public abstract ReadOnlyCollection<MetaType> DerivedTypes { get; }
204         /// <summary>
205         /// Gets an enumeration of all the data members (fields and properties).
206         /// </summary>
207         public abstract ReadOnlyCollection<MetaDataMember> DataMembers { get; }
208         /// <summary>
209         /// Gets an enumeration of all the persistent data members (fields and properties mapped into database columns).
210         /// </summary>
211         public abstract ReadOnlyCollection<MetaDataMember> PersistentDataMembers { get; }
212         /// <summary>
213         /// Gets an enumeration of all the data members that define up the unique identity of the type.
214         /// </summary>
215         public abstract ReadOnlyCollection<MetaDataMember> IdentityMembers { get; }
216         /// <summary>
217         /// Gets an enumeration of all the associations.
218         /// </summary>
219         public abstract ReadOnlyCollection<MetaAssociation> Associations { get; }
220         /// <summary>
221         /// Gets the MetaDataMember associated with the specified member.
222         /// </summary>
223         /// <param name="member">The CLR member.</param>
224         /// <returns>The MetaDataMember if there is one, otherwise null.</returns>
GetDataMember(MemberInfo member)225         public abstract MetaDataMember GetDataMember(MemberInfo member);
226         /// <summary>
227         /// The method called when the entity is first loaded.
228         /// </summary>
229         public abstract MethodInfo OnLoadedMethod { get; }
230         /// <summary>
231         /// The method called to ensure the entity is in a valid state.
232         /// </summary>
233         public abstract MethodInfo OnValidateMethod { get; }
234     }
235 
236     /// <summary>
237     /// A MetaDataMember represents the mapping between a domain object's field or property into a database table's column.
238     /// </summary>
239     [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "MetaData", Justification = "The capitalization was deliberately chosen.")]
240     public abstract class MetaDataMember {
241         /// <summary>
242         /// The MetaType containing this data member.
243         /// </summary>
244         public abstract MetaType DeclaringType { get; }
245         /// <summary>
246         /// The underlying MemberInfo.
247         /// </summary>
248         public abstract MemberInfo Member { get; }
249         /// <summary>
250         /// The member that actually stores this member's data.
251         /// </summary>
252         public abstract MemberInfo StorageMember { get; }
253         /// <summary>
254         /// The name of the member, same as the MemberInfo name.
255         /// </summary>
256         public abstract string Name { get; }
257         /// <summary>
258         /// The name of the column (or constraint) in the database.
259         /// </summary>
260         public abstract string MappedName { get; }
261         /// <summary>
262         /// The oridinal position of this member in the default layout of query results.
263         /// </summary>
264         public abstract int Ordinal { get; }
265         /// <summary>
266         /// The type of this member.
267         /// </summary>
268         [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The contexts in which this is available are fairly specific.")]
269         public abstract Type Type { get; }
270         /// <summary>
271         /// True if this member is declared by the specified type.
272         /// </summary>
273         /// <param name="type">Type to check.</param>
IsDeclaredBy(MetaType type)274         public abstract bool IsDeclaredBy(MetaType type);
275         /// <summary>
276         /// The accessor used to get/set the value of this member.
277         /// </summary>
278         public abstract MetaAccessor MemberAccessor { get; }
279         /// <summary>
280         /// The accessor used to get/set the storage value of this member.
281         /// </summary>
282         public abstract MetaAccessor StorageAccessor { get; }
283         /// <summary>
284         /// The accessor used to get/set the deferred value of this member (without causing fetch).
285         /// </summary>
286         public abstract MetaAccessor DeferredValueAccessor { get; }
287         /// <summary>
288         /// The accessor used to get/set the deferred source of this member.
289         /// </summary>
290         public abstract MetaAccessor DeferredSourceAccessor { get; }
291         /// <summary>
292         /// True if this member is defer-loaded by default.
293         /// </summary>
294         public abstract bool IsDeferred { get; }
295         /// <summary>
296         /// True if this member is mapped to a column (or constraint).
297         /// </summary>
298         public abstract bool IsPersistent { get; }
299         /// <summary>
300         /// True if this member defines an association relationship.
301         /// </summary>
302         public abstract bool IsAssociation { get; }
303         /// <summary>
304         /// True if this member is part of the type's identity.
305         /// </summary>
306         public abstract bool IsPrimaryKey { get; }
307         /// <summary>
308         /// True if this member is automatically generated by the database.
309         /// </summary>
310         [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification = "Conforms to legacy spelling.")]
311         public abstract bool IsDbGenerated { get; }
312         /// <summary>
313         /// True if this member represents the row version or timestamp.
314         /// </summary>
315         public abstract bool IsVersion { get; }
316         /// <summary>
317         /// True if this member represents the inheritance discriminator.
318         /// </summary>
319         public abstract bool IsDiscriminator { get; }
320         /// <summary>
321         /// True if this member's value can be assigned the null value.
322         /// </summary>
323         public abstract bool CanBeNull { get; }
324         /// <summary>
325         /// The type of the database column.
326         /// </summary>
327         [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification = "Conforms to legacy spelling.")]
328         public abstract string DbType { get; }
329         /// <summary>
330         /// Expression defining a computed column.
331         /// </summary>
332         public abstract string Expression { get; }
333         /// <summary>
334         /// The optimistic concurrency check policy for this member.
335         /// </summary>
336         public abstract UpdateCheck UpdateCheck { get; }
337         /// <summary>
338         /// Specifies for inserts and updates when this member should be read back after the
339         /// operation completes.
340         /// </summary>
341         public abstract AutoSync AutoSync { get; }
342         /// <summary>
343         /// The MetaAssociation corresponding to this member, or null if there is none.
344         /// </summary>
345         public abstract MetaAssociation Association { get; }
346         /// <summary>
347         /// The DataContext method used to perform load operations
348         /// </summary>
349         public abstract MethodInfo LoadMethod { get; }
350     }
351 
352     /// <summary>
353     /// A MetaFunction represents the mapping between a context method and a database function.
354     /// </summary>
355     public abstract class MetaFunction {
356         /// <summary>
357         /// The MetaModel containing this function.
358         /// </summary>
359         public abstract MetaModel Model { get; }
360         /// <summary>
361         /// The underlying context method.
362         /// </summary>
363         public abstract MethodInfo Method { get; }
364         /// <summary>
365         /// The name of the method (same as the MethodInfo's name).
366         /// </summary>
367         public abstract string Name { get; }
368         /// <summary>
369         /// The name of the database function or procedure.
370         /// </summary>
371         public abstract string MappedName { get; }
372         /// <summary>
373         /// True if the function can be composed within a query
374         /// </summary>
375         [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Composable", Justification="Spelling is correct.")]
376         public abstract bool IsComposable { get; }
377         /// <summary>
378         /// Gets an enumeration of the function parameters.
379         /// </summary>
380         /// <returns></returns>
381         public abstract ReadOnlyCollection<MetaParameter> Parameters { get; }
382         /// <summary>
383         /// The return parameter
384         /// </summary>
385         public abstract MetaParameter ReturnParameter { get; }
386         /// <summary>
387         /// True if the stored procedure has multiple result types.
388         /// </summary>
389         public abstract bool HasMultipleResults { get; }
390         /// <summary>
391         /// An enumeration of all the known result row types of a stored-procedure.
392         /// </summary>
393         /// <returns>Enumeration of possible result row types.</returns>
394         public abstract ReadOnlyCollection<MetaType> ResultRowTypes { get; }
395     }
396 
397     /// <summary>
398     /// A MetaParameter represents the mapping between a method parameter and a database function parameter.
399     /// </summary>
400     public abstract class MetaParameter {
401         /// <summary>
402         /// The underlying method parameter.
403         /// </summary>
404         public abstract ParameterInfo Parameter { get; }
405         /// <summary>
406         /// The name of the parameter (same as the ParameterInfo's name).
407         /// </summary>
408         public abstract string Name { get; }
409         /// <summary>
410         /// The name of the database function's parameter.
411         /// </summary>
412         public abstract string MappedName { get; }
413         /// <summary>
414         /// The CLR type of the parameter.
415         /// </summary>
416         public abstract Type ParameterType { get; }
417         /// <summary>
418         /// The database type of the parameter.
419         /// </summary>
420         [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db", Justification = "Conforms to legacy spelling.")]
421         public abstract string DbType { get; }
422     }
423 
424     /// <summary>
425     /// A MetaAssociation represents an association relationship between two entity types.
426     /// </summary>
427     public abstract class MetaAssociation {
428         /// <summary>
429         /// The type on the other end of the association.
430         /// </summary>
431         public abstract MetaType OtherType { get; }
432         /// <summary>
433         /// The member on this side that represents the association.
434         /// </summary>
435         public abstract MetaDataMember ThisMember { get; }
436         /// <summary>
437         /// The member on the other side of this association that represents the reverse association (may be null).
438         /// </summary>
439         public abstract MetaDataMember OtherMember { get; }
440         /// <summary>
441         /// A list of members representing the values on this side of the association.
442         /// </summary>
443         public abstract ReadOnlyCollection<MetaDataMember> ThisKey { get; }
444         /// <summary>
445         /// A list of members representing the values on the other side of the association.
446         /// </summary>
447         public abstract ReadOnlyCollection<MetaDataMember> OtherKey { get; }
448         /// <summary>
449         /// True if the association is OneToMany.
450         /// </summary>
451         public abstract bool IsMany { get; }
452         /// <summary>
453         /// True if the other type is the parent of this type.
454         /// </summary>
455         public abstract bool IsForeignKey { get; }
456         /// <summary>
457         /// True if the association is unique (defines a uniqueness constraint).
458         /// </summary>
459         public abstract bool IsUnique { get; }
460         /// <summary>
461         /// True if the association may be null (key values).
462         /// </summary>
463         public abstract bool IsNullable { get; }
464         /// <summary>
465         /// True if the ThisKey forms the identity (primary key) of the this type.
466         /// </summary>
467         public abstract bool ThisKeyIsPrimaryKey { get; }
468         /// <summary>
469         /// True if the OtherKey forms the identity (primary key) of the other type.
470         /// </summary>
471         public abstract bool OtherKeyIsPrimaryKey { get; }
472         /// <summary>
473         /// Specifies the behavior when the child is deleted (e.g. CASCADE, SET NULL).
474         /// Returns null if no action is specified on delete.
475         /// </summary>
476         public abstract string DeleteRule { get; }
477         /// <summary>
478         /// Specifies whether the object should be deleted when this association
479         /// is set to null.
480         /// </summary>
481         public abstract bool DeleteOnNull { get; }
482     }
483 
484     /// <summary>
485     /// A MetaAccessor
486     /// </summary>
487     public abstract class MetaAccessor {
488         /// <summary>
489         /// The type of the member accessed by this accessor.
490         /// </summary>
491         [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "The contexts in which this is available are fairly specific.")]
492         public abstract Type Type { get; }
493         /// <summary>
494         /// Gets the value as an object.
495         /// </summary>
496         /// <param name="instance">The instance to get the value from.</param>
497         /// <returns>Value.</returns>
GetBoxedValue(object instance)498         public abstract object GetBoxedValue(object instance);
499         /// <summary>
500         /// Sets the value as an object.
501         /// </summary>
502         /// <param name="instance">The instance to set the value into.</param>
503         /// <param name="value">The value to set.</param>
504         [SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate", Justification="Microsoft: Needs to handle classes and structs.")]
505         [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification="Unknown reason.")]
SetBoxedValue(ref object instance, object value)506         public abstract void SetBoxedValue(ref object instance, object value);
507         /// <summary>
508         /// True if the instance has a loaded or assigned value.
509         /// </summary>
HasValue(object instance)510         public virtual bool HasValue(object instance) {
511             return true;
512         }
513         /// <summary>
514         /// True if the instance has an assigned value.
515         /// </summary>
HasAssignedValue(object instance)516         public virtual bool HasAssignedValue(object instance) {
517             return true;
518         }
519         /// <summary>
520         /// True if the instance has a value loaded from a deferred source.
521         /// </summary>
HasLoadedValue(object instance)522         public virtual bool HasLoadedValue(object instance) {
523             return false;
524         }
525     }
526 
527     /// <summary>
528     /// A strongly-typed MetaAccessor. Used for reading from and writing to
529     /// CLR objects.
530     /// </summary>
531     /// <typeparam name="T">The type of the object</typeparam>
532     /// <typeparam name="V">The type of the accessed member</typeparam>
533     public abstract class MetaAccessor<TEntity, TMember> : MetaAccessor {
534         /// <summary>
535         /// The underlying CLR type.
536         /// </summary>
537         public override Type Type {
538             get { return typeof(TMember); }
539         }
540         /// <summary>
541         /// Set the boxed value on an instance.
542         /// </summary>
SetBoxedValue(ref object instance, object value)543         public override void SetBoxedValue(ref object instance, object value) {
544             TEntity tInst = (TEntity)instance;
545             this.SetValue(ref tInst, (TMember)value);
546             instance = tInst;
547         }
548         /// <summary>
549         /// Retrieve the boxed value.
550         /// </summary>
GetBoxedValue(object instance)551         public override object GetBoxedValue(object instance) {
552             return this.GetValue((TEntity)instance);
553         }
554         /// <summary>
555         /// Gets the strongly-typed value.
556         /// </summary>
GetValue(TEntity instance)557         public abstract TMember GetValue(TEntity instance);
558         /// <summary>
559         /// Sets the strongly-typed value
560         /// </summary>
561         [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "0#", Justification = "Unknown reason.")]
SetValue(ref TEntity instance, TMember value)562         public abstract void SetValue(ref TEntity instance, TMember value);
563     }
564 }
565