2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Collections.ObjectModel;
5 using System.Linq.Expressions;
6 using System.Reflection;
9 using System.Data.Linq.Provider;
10 using System.Data.Linq.Mapping;
11 using System.Data.Linq.SqlClient;
12 using System.Threading;
13 using System.Runtime.Versioning;
14 using LinqToSqlShared.Mapping;
15 using System.Runtime.CompilerServices;
17 namespace System.Data.Linq.Mapping {
19 internal class MappedMetaModel : MetaModel {
20 ReaderWriterLock @lock = new ReaderWriterLock();
21 MappingSource mappingSource;
24 DatabaseMapping mapping;
25 HashSet<Module> modules;
26 Dictionary<string, Type> types;
27 Dictionary<Type, MetaType> metaTypes;
28 Dictionary<Type, MetaTable> metaTables;
29 Dictionary<MetaPosition, MetaFunction> metaFunctions;
32 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // mapping parameter contains various type references.
33 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call.
34 internal MappedMetaModel(MappingSource mappingSource, Type contextType, DatabaseMapping mapping) {
35 this.mappingSource = mappingSource;
36 this.contextType = contextType;
37 this.mapping = mapping;
38 this.modules = new HashSet<Module>();
39 this.modules.Add(this.contextType.Module);
40 this.metaTypes = new Dictionary<Type, MetaType>();
41 this.metaTables = new Dictionary<Type, MetaTable>();
42 this.types = new Dictionary<string, Type>();
44 if (this.providerType == null && !String.IsNullOrEmpty(this.mapping.Provider)) {
45 this.providerType = this.FindType(this.mapping.Provider, typeof(SqlProvider).Namespace);
46 if (this.providerType == null) {
47 throw Error.ProviderTypeNotFound(this.mapping.Provider);
50 else if (this.providerType == null) {
51 this.providerType = typeof(SqlProvider);
55 #region Initialization
58 // The fullyLoaded state is required so that tools like
59 // CreateDatabase can get a full view of all tables.
60 @lock.AcquireWriterLock(Timeout.Infinite);
63 // Initialize static tables and functions.
64 this.InitStaticTables();
70 @lock.ReleaseWriterLock();
75 [ResourceExposure(ResourceScope.None)] // Exposure is via external mapping file/attributes.
76 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine, ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call.
77 private void InitStaticTables() {
78 this.InitStaticTableTypes();
79 foreach (TableMapping tableMapping in this.mapping.Tables) {
80 Type rowType = this.FindType(tableMapping.RowType.Name);
81 if (rowType == null) {
82 throw Error.CouldNotFindTypeFromMapping(tableMapping.RowType.Name);
84 Type rootType = this.GetRootType(rowType, tableMapping.RowType);
85 MetaTable table = new MappedTable(this, tableMapping, rootType);
86 foreach (MetaType mt in table.RowType.InheritanceTypes) {
87 this.metaTypes.Add(mt.Type, mt);
88 this.metaTables.Add(mt.Type, table);
93 private void InitStaticTableTypes() {
94 for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) {
95 FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
96 foreach (FieldInfo fi in fields) {
97 Type ft = fi.FieldType;
98 if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Table<>)) {
99 Type rowType = ft.GetGenericArguments()[0];
100 if (!this.types.ContainsKey(rowType.Name)) {
101 this.types.Add(rowType.FullName, rowType);
102 if (!this.types.ContainsKey(rowType.Name)) {
103 this.types.Add(rowType.Name, rowType);
105 this.modules.Add(rowType.Module);
109 PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
110 foreach (PropertyInfo pi in props) {
111 Type pt = pi.PropertyType;
112 if (pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Table<>)) {
113 Type rowType = pt.GetGenericArguments()[0];
114 if (!this.types.ContainsKey(rowType.Name)) {
115 this.types.Add(rowType.FullName, rowType);
116 if (!this.types.ContainsKey(rowType.Name)) {
117 this.types.Add(rowType.Name, rowType);
119 this.modules.Add(rowType.Module);
126 [ResourceExposure(ResourceScope.None)] // mapping instance variable is set elsewhere.
127 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine, ResourceScope.Assembly | ResourceScope.Machine)] // For GetMethods call.
128 private void InitFunctions() {
129 this.metaFunctions = new Dictionary<MetaPosition, MetaFunction>();
130 if (this.contextType != typeof(DataContext)) {
131 foreach (FunctionMapping fmap in this.mapping.Functions) {
132 MethodInfo method = this.GetMethod(fmap.MethodName);
133 if (method == null) {
134 throw Error.MethodCannotBeFound(fmap.MethodName);
136 MappedFunction func = new MappedFunction(this, fmap, method);
137 this.metaFunctions.Add(new MetaPosition(method), func);
139 // pre-set all known function result types into metaType map
140 foreach (MetaType rt in func.ResultRowTypes) {
141 foreach (MetaType it in rt.InheritanceTypes) {
142 if (!this.metaTypes.ContainsKey(it.Type)) {
143 this.metaTypes.Add(it.Type, it);
152 public override MappingSource MappingSource {
153 get { return this.mappingSource; }
156 public override Type ContextType {
157 get { return this.contextType; }
160 public override string DatabaseName {
161 get { return this.mapping.DatabaseName; }
164 public override Type ProviderType {
165 get { return this.providerType; }
168 public override IEnumerable<MetaTable> GetTables() {
169 return this.metaTables.Values.Where(x => x != null).Distinct();
172 public override MetaTable GetTable(Type rowType) {
173 if (rowType == null) {
174 throw Error.ArgumentNull("rowType");
176 MetaTable table = null;
177 this.metaTables.TryGetValue(rowType, out table);
181 public override MetaType GetMetaType(Type type) {
183 throw Error.ArgumentNull("type");
185 MetaType mtype = null;
186 @lock.AcquireReaderLock(Timeout.Infinite);
188 if (this.metaTypes.TryGetValue(type, out mtype)) {
193 @lock.ReleaseReaderLock();
195 @lock.AcquireWriterLock(Timeout.Infinite);
197 if (!this.metaTypes.TryGetValue(type, out mtype)) {
198 // not known, so must be unmapped type
199 mtype = new UnmappedType(this, type);
200 this.metaTypes.Add(type, mtype);
204 @lock.ReleaseWriterLock();
209 public override MetaFunction GetFunction(MethodInfo method) {
210 if (method == null) {
211 throw new ArgumentNullException("method");
213 MetaFunction func = null;
214 this.metaFunctions.TryGetValue(new MetaPosition(method), out func);
218 public override IEnumerable<MetaFunction> GetFunctions() {
219 return this.metaFunctions.Values;
222 private Type GetRootType(Type type, TypeMapping rootMapping) {
223 if (string.Compare(rootMapping.Name, type.Name, StringComparison.Ordinal) == 0
224 || string.Compare(rootMapping.Name, type.FullName, StringComparison.Ordinal) == 0
225 || string.Compare(rootMapping.Name, type.AssemblyQualifiedName, StringComparison.Ordinal) == 0)
227 if (type.BaseType != typeof(object)) {
228 return this.GetRootType(type.BaseType, rootMapping);
230 throw Error.UnableToResolveRootForType(type);
233 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter will be found on a type.
234 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call.
235 private MethodInfo GetMethod(string name) {
236 string typeName, methodName;
237 this.GetTypeAndMethod(name, out typeName, out methodName);
238 Type type = this.FindType(typeName);
240 return type.GetMethod(methodName, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
245 private void GetTypeAndMethod(string name, out string typeName, out string methodName) {
246 int dotIndex = name.LastIndexOf(".", StringComparison.CurrentCulture);
248 typeName = name.Substring(0, dotIndex);
249 methodName = name.Substring(dotIndex + 1);
252 typeName = this.contextType.FullName;
257 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter is a type name.
258 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call.
259 internal Type FindType(string name) {
260 return this.FindType(name, this.contextType.Namespace);
263 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter is a type name.
264 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // SearchForType method call.
265 internal Type FindType(string name, string defaultNamespace) {
268 @lock.AcquireReaderLock(Timeout.Infinite);
270 if (this.types.TryGetValue(name, out result)) {
273 name2 = name.Contains(".") ? null : defaultNamespace + "." + name;
274 if (name2 != null && this.types.TryGetValue(name2, out result)) {
279 @lock.ReleaseReaderLock();
281 // don't block anyone while we search for the correct type
282 Type foundResult = this.SearchForType(name);
284 if (foundResult == null && name2 != null) {
285 foundResult = this.SearchForType(name2);
287 if (foundResult != null) {
288 @lock.AcquireWriterLock(Timeout.Infinite);
290 if (this.types.TryGetValue(name, out result)) {
293 this.types.Add(name, foundResult);
297 @lock.ReleaseWriterLock();
303 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter is a type name.
304 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // SearchForType method call.
305 private Type SearchForType(string name) {
306 // Try search for type using case sensitive.
307 Type type = SearchForType(name, false);
312 // Try search for type using case in-sensitive.
313 return SearchForType(name, true);
316 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter is a type name.
317 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // Assembly.GetLoadedModules method call.
318 private Type SearchForType(string name, bool ignoreCase) {
319 // first try default system lookup
320 Type type = Type.GetType(name, false, ignoreCase);
325 // try all known modules (modules that other statically known types were found in)
326 foreach (Module module in this.modules) {
327 type = module.GetType(name, false, ignoreCase);
333 // try all loaded modules (is there a better way?)
334 foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) {
335 foreach (Module module in a.GetLoadedModules()) {
336 type = module.GetType(name, false, ignoreCase);
347 internal sealed class MappedTable : MetaTable {
348 MappedMetaModel model;
349 TableMapping mapping;
352 MethodInfo insertMethod;
353 MethodInfo updateMethod;
354 MethodInfo deleteMethod;
356 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // Parameter contains various type references.
357 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // MappedRootType constructor call.
358 internal MappedTable(MappedMetaModel model, TableMapping mapping, Type rowType) {
360 this.mapping = mapping;
361 this.rowType = new MappedRootType(model, this, mapping.RowType, rowType);
363 public override MetaModel Model {
364 get { return this.model; }
366 public override string TableName {
367 get { return this.mapping.TableName; }
369 public override MetaType RowType {
370 get { return this.rowType; }
372 public override MethodInfo InsertMethod {
375 return this.insertMethod;
378 public override MethodInfo UpdateMethod {
381 return this.updateMethod;
384 public override MethodInfo DeleteMethod {
387 return this.deleteMethod;
390 private void InitMethods() {
391 if (!this.hasMethods) {
392 this.insertMethod = MethodFinder.FindMethod(
393 this.model.ContextType,
394 "Insert" + rowType.Name,
395 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
396 new Type[] { rowType.Type }
398 this.updateMethod = MethodFinder.FindMethod(
399 this.model.ContextType,
400 "Update" + rowType.Name,
401 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
402 new Type[] { rowType.Type }
404 this.deleteMethod = MethodFinder.FindMethod(
405 this.model.ContextType,
406 "Delete" + rowType.Name,
407 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
408 new Type[] { rowType.Type }
410 this.hasMethods = true;
415 internal sealed class MappedRootType : MappedType {
416 Dictionary<Type, MetaType> derivedTypes;
417 Dictionary<object, MetaType> inheritanceCodes;
418 ReadOnlyCollection<MetaType> inheritanceTypes;
419 MetaType inheritanceDefault;
422 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // Various parameters can contain type names.
423 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // InitInheritedType method call.
424 public MappedRootType(MappedMetaModel model, MappedTable table, TypeMapping typeMapping, Type type)
425 : base(model, table, typeMapping, type, null) {
426 if (typeMapping == null)
427 throw Error.ArgumentNull("typeMapping");
429 if (typeMapping.InheritanceCode != null || typeMapping.DerivedTypes.Count > 0) {
430 if (this.Discriminator == null) {
431 throw Error.NoDiscriminatorFound(type.Name);
433 this.hasInheritance = true;
434 if (!MappingSystem.IsSupportedDiscriminatorType(this.Discriminator.Type)) {
435 throw Error.DiscriminatorClrTypeNotSupported(this.Discriminator.DeclaringType.Name, this.Discriminator.Name, this.Discriminator.Type);
437 this.derivedTypes = new Dictionary<Type, MetaType>();
438 this.inheritanceCodes = new Dictionary<object, MetaType>();
439 this.InitInheritedType(typeMapping, this);
442 if (this.inheritanceDefault == null && (this.inheritanceCode != null || this.inheritanceCodes != null && this.inheritanceCodes.Count > 0))
443 throw Error.InheritanceHierarchyDoesNotDefineDefault(type);
445 if (this.derivedTypes != null) {
446 this.inheritanceTypes = this.derivedTypes.Values.ToList().AsReadOnly();
449 this.inheritanceTypes = new MetaType[] { this }.ToList().AsReadOnly();
455 private void Validate() {
456 Dictionary<object, string> memberToColumn = new Dictionary<object, string>();
457 foreach (MetaType type in this.InheritanceTypes) {
458 // NB: Table node in XML can have only one Type node -- enforced by XSD
460 foreach (MetaDataMember mem in type.PersistentDataMembers) {
461 if (mem.IsDeclaredBy(type)) {
462 if (mem.IsDiscriminator && !this.HasInheritance) {
463 throw Error.NonInheritanceClassHasDiscriminator(type);
465 if (!mem.IsAssociation) {
466 // validate that no database column is mapped twice
467 if (!string.IsNullOrEmpty(mem.MappedName)) {
469 object dn = InheritanceRules.DistinguishedMemberName(mem.Member);
470 if (memberToColumn.TryGetValue(dn, out column)) {
471 if (column != mem.MappedName) {
472 throw Error.MemberMappedMoreThanOnce(mem.Member.Name);
476 memberToColumn.Add(dn, mem.MappedName);
485 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // typeMap parameter's Name property.
486 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call.
487 private MetaType InitDerivedTypes(TypeMapping typeMap) {
488 Type type = ((MappedMetaModel)Model).FindType(typeMap.Name);
490 throw Error.CouldNotFindRuntimeTypeForMapping(typeMap.Name);
491 MappedType rowType = new MappedType(this.Model, this.Table, typeMap, type, this);
492 return this.InitInheritedType(typeMap, rowType);
495 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // typeMap parameter's Name property.
496 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // InitDerivedTypes method call.
497 private MetaType InitInheritedType(TypeMapping typeMap, MappedType type) {
498 this.derivedTypes.Add(type.Type, type);
500 if (typeMap.InheritanceCode != null) { // Mapping with no inheritance code: For example, an unmapped intermediate class in a hierarchy.
501 if (this.Discriminator == null)
502 throw Error.NoDiscriminatorFound(type.Name);
504 if (type.Type.IsAbstract)
505 throw Error.AbstractClassAssignInheritanceDiscriminator(type.Type);
507 object keyValue = DBConvert.ChangeType(typeMap.InheritanceCode, this.Discriminator.Type);
508 foreach (object d in inheritanceCodes.Keys) {
509 // if the keys are equal, or if they are both strings containing only spaces
510 // they are considered equal
511 if ((keyValue.GetType() == typeof(string) && ((string)keyValue).Trim().Length == 0 &&
512 d.GetType() == typeof(string) && ((string)d).Trim().Length == 0) ||
513 object.Equals(d, keyValue)) {
514 throw Error.InheritanceCodeUsedForMultipleTypes(keyValue);
517 if (type.inheritanceCode != null)
518 throw Error.InheritanceTypeHasMultipleDiscriminators(type);
519 type.inheritanceCode = keyValue;
520 this.inheritanceCodes.Add(keyValue, type);
521 if (typeMap.IsInheritanceDefault) {
522 if (this.inheritanceDefault != null)
523 throw Error.InheritanceTypeHasMultipleDefaults(type);
524 this.inheritanceDefault = type;
528 // init sub-inherited types
529 foreach (TypeMapping tm in typeMap.DerivedTypes) {
530 this.InitDerivedTypes(tm);
536 public override bool HasInheritance {
537 get { return this.hasInheritance; }
540 public override bool HasInheritanceCode {
541 get { return this.InheritanceCode != null; }
544 public override ReadOnlyCollection<MetaType> InheritanceTypes {
545 get { return this.inheritanceTypes; }
548 public override MetaType GetInheritanceType(Type type) {
549 if (type == this.Type)
551 MetaType metaType = null;
552 if (this.derivedTypes != null) {
553 this.derivedTypes.TryGetValue(type, out metaType);
558 public override MetaType InheritanceDefault {
559 get { return this.inheritanceDefault; }
563 internal class MappedType : MetaType {
567 TypeMapping typeMapping;
568 Dictionary<object, MetaDataMember> dataMemberMap;
569 ReadOnlyCollection<MetaDataMember> dataMembers;
570 ReadOnlyCollection<MetaDataMember> persistentDataMembers;
571 ReadOnlyCollection<MetaDataMember> identities;
572 MetaDataMember dbGeneratedIdentity;
573 MetaDataMember version;
574 MetaDataMember discriminator;
575 MetaType inheritanceRoot;
576 bool inheritanceBaseSet;
577 MetaType inheritanceBase;
578 internal object inheritanceCode;
579 ReadOnlyCollection<MetaType> derivedTypes;
580 ReadOnlyCollection<MetaAssociation> associations;
582 bool hasAnyLoadMethod;
583 bool hasAnyValidateMethod;
584 MethodInfo onLoadedMethod;
585 MethodInfo onValidateMethod;
587 object locktarget = new object(); // Hold locks on private object rather than public MetaType.
589 internal MappedType(MetaModel model, MetaTable table, TypeMapping typeMapping, Type type, MetaType inheritanceRoot) {
592 this.typeMapping = typeMapping;
594 this.inheritanceRoot = inheritanceRoot != null ? inheritanceRoot : this;
595 this.InitDataMembers();
597 this.identities = this.dataMembers.Where(m => m.IsPrimaryKey).ToList().AsReadOnly();
598 this.persistentDataMembers = this.dataMembers.Where(m => m.IsPersistent).ToList().AsReadOnly();
600 #region Initialization
601 private void ValidatePrimaryKeyMember(MetaDataMember mm) {
602 //if the type is a sub-type, no member in the type can be primary key
603 if (mm.IsPrimaryKey && this.inheritanceRoot != this && mm.Member.DeclaringType == this.type) {
604 throw (Error.PrimaryKeyInSubTypeNotSupported(this.type.Name, mm.Name));
608 private void InitMethods() {
609 if (!this.hasMethods) {
610 this.onLoadedMethod = MethodFinder.FindMethod(
613 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
617 this.onValidateMethod = MethodFinder.FindMethod(
620 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
621 new[] { typeof(ChangeAction) },
625 this.hasAnyLoadMethod = (this.onLoadedMethod != null) || (this.InheritanceBase != null && this.InheritanceBase.HasAnyLoadMethod);
626 this.hasAnyValidateMethod = (this.onValidateMethod != null) || (this.InheritanceBase != null && this.InheritanceBase.HasAnyValidateMethod);
628 this.hasMethods = true;
632 private void InitDataMembers() {
633 if (this.dataMembers == null) {
634 Dictionary<object, MetaDataMember> map = new Dictionary<object, MetaDataMember>();
635 List<MetaDataMember> dMembers = new List<MetaDataMember>();
637 BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
639 // Map of valid mapped names.
640 Dictionary<string, MemberMapping> names = new Dictionary<string, MemberMapping>();
641 Type currentType = this.type;
642 for (TypeMapping tm = this.typeMapping; tm != null; tm = tm.BaseType) {
643 foreach (MemberMapping mmap in tm.Members) {
644 names[mmap.MemberName + ":" + currentType.Name] = mmap;
646 currentType = currentType.BaseType;
649 HashSet<string> namesSeen = new HashSet<string>(); // Keep track of which names from the mapping file have been seen.
650 FieldInfo[] fis = TypeSystem.GetAllFields(this.type, flags).ToArray();
652 foreach (FieldInfo fi in fis) {
654 string name = fi.Name + ":" + fi.DeclaringType.Name;
655 if (names.TryGetValue(name, out mmap)) {
657 object dn = InheritanceRules.DistinguishedMemberName(fi);
659 if (!map.TryGetValue(dn, out mm)) {
660 mm = new MappedDataMember(this, fi, mmap, ordinal);
661 map.Add(InheritanceRules.DistinguishedMemberName(mm.Member), mm);
663 this.InitSpecialMember(mm);
665 ValidatePrimaryKeyMember(mm);
671 PropertyInfo[] pis = TypeSystem.GetAllProperties(this.type, flags).ToArray();
673 foreach (PropertyInfo pi in pis) {
675 string name = pi.Name + ":" + pi.DeclaringType.Name;
676 if (names.TryGetValue(name, out mmap)) {
679 object dn = InheritanceRules.DistinguishedMemberName(pi);
680 if (!map.TryGetValue(dn, out mm)) {
681 mm = new MappedDataMember(this, pi, mmap, ordinal);
682 map.Add(InheritanceRules.DistinguishedMemberName(mm.Member), mm);
684 this.InitSpecialMember(mm);
686 ValidatePrimaryKeyMember(mm);
692 this.dataMembers = dMembers.AsReadOnly();
693 this.dataMemberMap = map;
695 // Finally, make sure that all types in the mapping file were consumed.
696 foreach(string name in namesSeen) {
699 foreach(var orphan in names) {
700 Type aboveRoot = inheritanceRoot.Type.BaseType;
701 while (aboveRoot!=null) {
702 foreach(MemberInfo mi in aboveRoot.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
703 if(String.Compare(mi.Name, orphan.Value.MemberName, StringComparison.Ordinal)==0) {
704 throw Error.MappedMemberHadNoCorrespondingMemberInType(orphan.Value.MemberName, type.Name);
707 aboveRoot = aboveRoot.BaseType;
712 private void InitSpecialMember(MetaDataMember mm) {
713 // Can only have one auto gen member that is also an identity member,
714 // except if that member is a computed column (since they are implicitly auto gen)
715 if (mm.IsDbGenerated && mm.IsPrimaryKey && string.IsNullOrEmpty(mm.Expression)) {
716 if (this.dbGeneratedIdentity != null) {
717 throw Error.TwoMembersMarkedAsPrimaryKeyAndDBGenerated(mm.Member, this.dbGeneratedIdentity.Member);
719 this.dbGeneratedIdentity = mm;
721 if (mm.IsPrimaryKey && !MappingSystem.IsSupportedIdentityType(mm.Type))
723 throw Error.IdentityClrTypeNotSupported(mm.DeclaringType, mm.Name, mm.Type);
726 if (this.version != null) {
727 throw Error.TwoMembersMarkedAsRowVersion(mm.Member, this.version.Member);
731 if (mm.IsDiscriminator) {
732 if (this.discriminator != null) {
733 if (!InheritanceRules.AreSameMember(this.discriminator.Member, mm.Member)) {
734 throw Error.TwoMembersMarkedAsInheritanceDiscriminator(mm.Member, this.discriminator.Member);
738 this.discriminator = mm;
743 public override MetaModel Model {
744 get { return this.model; }
746 public override MetaTable Table {
747 get { return this.table; }
749 public override Type Type {
750 get { return this.type; }
752 public override string Name {
753 get { return this.type.Name; }
755 public override bool IsEntity {
757 if (this.table != null) {
758 return table.RowType.IdentityMembers.Count > 0;
764 public override bool CanInstantiate {
765 get { return !this.type.IsAbstract && (this == this.InheritanceRoot || this.HasInheritanceCode); }
767 public override MetaDataMember DBGeneratedIdentityMember {
768 get { return this.dbGeneratedIdentity; }
770 public override MetaDataMember VersionMember {
771 get { return this.version; }
773 public override MetaDataMember Discriminator {
774 get { return this.discriminator; }
776 public override bool HasUpdateCheck {
778 foreach (MetaDataMember member in this.PersistentDataMembers) {
779 if (member.UpdateCheck != UpdateCheck.Never) {
786 public override bool HasInheritance {
787 get { return this.inheritanceRoot.HasInheritance; }
789 public override object InheritanceCode {
790 get { return this.inheritanceCode; }
792 public override bool HasInheritanceCode {
793 get { return this.InheritanceCode != null; }
795 public override bool IsInheritanceDefault {
796 get { return this.InheritanceDefault == this; }
798 public override MetaType InheritanceDefault {
800 if (this.inheritanceRoot == this)
801 throw Error.CannotGetInheritanceDefaultFromNonInheritanceClass();
802 return this.InheritanceRoot.InheritanceDefault;
805 public override MetaType InheritanceRoot {
806 get { return this.inheritanceRoot; }
808 public override MetaType InheritanceBase {
810 // LOCKING: Cannot initialize at construction
811 if (!this.inheritanceBaseSet && this.inheritanceBase == null) {
812 lock (this.locktarget) {
813 if (this.inheritanceBase == null) {
814 this.inheritanceBase = InheritanceBaseFinder.FindBase(this);
815 this.inheritanceBaseSet = true;
819 return this.inheritanceBase;
822 public override ReadOnlyCollection<MetaType> InheritanceTypes {
823 get { return this.inheritanceRoot.InheritanceTypes; }
825 public override ReadOnlyCollection<MetaType> DerivedTypes {
827 // LOCKING: Cannot initialize at construction because derived types
829 if (this.derivedTypes == null) {
830 lock (this.locktarget) {
831 if (this.derivedTypes == null) {
832 List<MetaType> dTypes = new List<MetaType>();
833 foreach (MetaType mt in this.InheritanceTypes) {
834 if (mt.Type.BaseType == this.type)
837 this.derivedTypes = dTypes.AsReadOnly();
841 return this.derivedTypes;
844 public override MetaType GetInheritanceType(Type inheritanceType) {
845 foreach (MetaType mt in this.InheritanceTypes)
846 if (mt.Type == inheritanceType)
850 public override MetaType GetTypeForInheritanceCode(object key) {
851 if (this.InheritanceRoot.Discriminator.Type == typeof(string)) {
852 string skey = (string)key;
853 foreach (MetaType mt in this.InheritanceRoot.InheritanceTypes) {
854 if (string.Compare((string)mt.InheritanceCode, skey, StringComparison.OrdinalIgnoreCase) == 0)
859 foreach (MetaType mt in this.InheritanceRoot.InheritanceTypes) {
860 if (object.Equals(mt.InheritanceCode, key))
866 public override ReadOnlyCollection<MetaDataMember> DataMembers {
867 get { return this.dataMembers; }
869 public override ReadOnlyCollection<MetaDataMember> PersistentDataMembers {
870 get { return this.persistentDataMembers; }
872 public override ReadOnlyCollection<MetaDataMember> IdentityMembers {
873 get { return this.identities; }
875 public override ReadOnlyCollection<MetaAssociation> Associations {
877 // LOCKING: Associations are late-expanded so that cycles are broken.
878 if (this.associations == null) {
879 lock (this.locktarget) {
880 if (this.associations == null) {
881 this.associations = this.dataMembers.Where(m => m.IsAssociation).Select(m => m.Association).ToList().AsReadOnly();
885 return this.associations;
888 public override MetaDataMember GetDataMember(MemberInfo mi) {
890 throw Error.ArgumentNull("mi");
892 if (this.dataMemberMap.TryGetValue(InheritanceRules.DistinguishedMemberName(mi), out mm)) {
895 if (mi.DeclaringType.IsInterface) {
896 throw Error.MappingOfInterfacesMemberIsNotSupported(mi.DeclaringType.Name, mi.Name);
897 } else { //the member is not mapped in the base class
898 throw Error.UnmappedClassMember(mi.DeclaringType.Name, mi.Name);
903 public override MethodInfo OnLoadedMethod {
906 return this.onLoadedMethod;
910 public override MethodInfo OnValidateMethod {
913 return this.onValidateMethod;
916 public override bool HasAnyValidateMethod {
919 return this.hasAnyValidateMethod;
922 public override bool HasAnyLoadMethod {
925 return this.hasAnyLoadMethod;
929 public override string ToString() {
934 internal sealed class MappedDataMember : MetaDataMember {
935 MetaType declaringType;
937 MemberInfo storageMember;
941 MetaAccessor accPublic;
942 MetaAccessor accPrivate;
943 MetaAccessor accDefValue;
944 MetaAccessor accDefSource;
945 MemberMapping memberMap;
946 MappedAssociation assoc;
952 bool isDiscriminator;
953 bool canBeNull = true;
957 UpdateCheck updateCheck = UpdateCheck.Never;
958 AutoSync autoSync = AutoSync.Never;
959 object locktarget = new object(); // Hold locks on private object rather than public MetaType.
961 MethodInfo loadMethod;
963 internal MappedDataMember(MetaType declaringType, MemberInfo mi, MemberMapping map, int ordinal) {
964 this.declaringType = declaringType;
966 this.ordinal = ordinal;
967 this.type = TypeSystem.GetMemberType(mi);
968 this.isNullableType = TypeSystem.IsNullableType(this.type);
969 this.memberMap = map;
970 if (this.memberMap != null && this.memberMap.StorageMemberName != null) {
971 MemberInfo[] mis = mi.DeclaringType.GetMember(this.memberMap.StorageMemberName, BindingFlags.Instance | BindingFlags.NonPublic);
972 if (mis == null || mis.Length != 1) {
973 throw Error.BadStorageProperty(this.memberMap.StorageMemberName, mi.DeclaringType, mi.Name);
975 this.storageMember = mis[0];
977 Type storageType = this.storageMember != null ? TypeSystem.GetMemberType(this.storageMember) : this.type;
978 this.isDeferred = IsDeferredType(storageType);
979 ColumnMapping cmap = map as ColumnMapping;
980 if (cmap != null && cmap.IsDbGenerated && cmap.IsPrimaryKey) {
981 // auto-gen identities must be synced on insert
982 if ((cmap.AutoSync != AutoSync.Default) && (cmap.AutoSync != AutoSync.OnInsert)) {
983 throw Error.IncorrectAutoSyncSpecification(mi.Name);
987 this.isPrimaryKey = cmap.IsPrimaryKey;
988 this.isVersion = cmap.IsVersion;
989 this.isDBGenerated = cmap.IsDbGenerated || !string.IsNullOrEmpty(cmap.Expression) || this.isVersion;
990 this.isDiscriminator = cmap.IsDiscriminator;
991 this.canBeNull = cmap.CanBeNull == null ? this.isNullableType || !this.type.IsValueType : (bool)cmap.CanBeNull;
992 this.dbType = cmap.DbType;
993 this.expression = cmap.Expression;
994 this.updateCheck = cmap.UpdateCheck;
995 // auto-gen keys are always and only synced on insert
996 if (this.IsDbGenerated && this.IsPrimaryKey) {
997 this.autoSync = AutoSync.OnInsert;
999 else if (cmap.AutoSync != AutoSync.Default) {
1000 // if the user has explicitly set it, use their value
1001 this.autoSync = cmap.AutoSync;
1003 else if (this.IsDbGenerated) {
1004 // database generated members default to always
1005 this.autoSync = AutoSync.Always;
1008 this.mappedName = this.memberMap.DbName != null ? this.memberMap.DbName : this.member.Name;
1010 private void InitAccessors() {
1011 if (!this.hasAccessors) {
1012 lock (this.locktarget) {
1013 if (!this.hasAccessors) {
1014 if (this.storageMember != null) {
1015 this.accPrivate = MakeMemberAccessor(this.member.ReflectedType, this.storageMember, null);
1016 if (this.isDeferred) {
1017 MakeDeferredAccessors(this.member.ReflectedType, this.accPrivate, out this.accPrivate, out this.accDefValue, out this.accDefSource);
1019 this.accPublic = MakeMemberAccessor(this.member.ReflectedType, this.member, this.accPrivate);
1022 this.accPublic = this.accPrivate = MakeMemberAccessor(this.member.ReflectedType, this.member, null);
1023 if (this.isDeferred) {
1024 MakeDeferredAccessors(this.member.ReflectedType, this.accPrivate, out this.accPrivate, out this.accDefValue, out this.accDefSource);
1027 this.hasAccessors = true;
1032 public override MetaType DeclaringType {
1033 get { return this.declaringType; }
1035 public override bool IsDeclaredBy(MetaType metaType) {
1036 if (metaType == null) {
1037 throw Error.ArgumentNull("metaType");
1039 return metaType.Type == this.member.DeclaringType;
1041 public override MemberInfo Member {
1042 get { return this.member; }
1044 public override MemberInfo StorageMember {
1045 get { return this.storageMember; }
1047 public override string Name {
1048 get { return this.member.Name; }
1050 public override int Ordinal {
1051 get { return this.ordinal; }
1053 public override Type Type {
1054 get { return this.type; }
1056 public override MetaAccessor MemberAccessor {
1058 this.InitAccessors();
1059 return this.accPublic;
1062 public override MetaAccessor StorageAccessor {
1064 this.InitAccessors();
1065 return this.accPrivate;
1068 public override MetaAccessor DeferredValueAccessor {
1070 this.InitAccessors();
1071 return this.accDefValue;
1074 public override MetaAccessor DeferredSourceAccessor {
1076 this.InitAccessors();
1077 return this.accDefSource;
1080 public override bool IsDeferred {
1081 get { return this.isDeferred; }
1083 public override bool IsPersistent {
1084 get { return this.memberMap != null; }
1086 public override bool IsAssociation {
1087 get { return this.memberMap is AssociationMapping; }
1089 public override bool IsPrimaryKey {
1090 get { return this.isPrimaryKey; }
1093 /// Returns true if the member is explicitly marked as auto gen, or if the
1094 /// member is computed or generated by the database server.
1096 public override bool IsDbGenerated {
1097 get { return this.isDBGenerated; }
1099 public override bool IsVersion {
1100 get { return this.isVersion; }
1102 public override bool IsDiscriminator {
1103 get { return this.isDiscriminator; }
1105 public override bool CanBeNull {
1106 get { return this.canBeNull; }
1108 public override string DbType {
1109 get { return this.dbType; }
1111 public override string Expression {
1112 get { return this.expression; }
1114 public override string MappedName {
1115 get { return this.mappedName; }
1117 public override UpdateCheck UpdateCheck {
1118 get { return this.updateCheck; }
1120 public override AutoSync AutoSync {
1121 get { return this.autoSync; }
1123 public override MetaAssociation Association {
1125 if (this.IsAssociation) {
1126 // LOCKING: This deferral isn't an optimization. It can't be done in the constructor
1127 // because there may be loops in the association graph.
1128 if (this.assoc == null) {
1129 lock (this.locktarget) {
1130 if (this.assoc == null) {
1131 this.assoc = new MappedAssociation(this, (AssociationMapping)this.memberMap);
1139 public override MethodInfo LoadMethod {
1141 if (this.hasLoadMethod == false && this.IsDeferred) {
1142 // defer searching for this access method until we really need to know
1143 this.loadMethod = MethodFinder.FindMethod(
1144 ((MappedMetaModel)this.declaringType.Model).ContextType,
1145 "Load" + this.member.Name,
1146 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
1147 new Type[] { this.DeclaringType.Type }
1149 this.hasLoadMethod = true;
1151 return this.loadMethod;
1154 private bool IsDeferredType(Type clrType) {
1155 if (clrType == null || clrType == typeof(object)) {
1158 if (clrType.IsGenericType) {
1159 Type gtype = clrType.GetGenericTypeDefinition();
1160 return gtype == typeof(Link<>) ||
1161 typeof(EntitySet<>).IsAssignableFrom(gtype) ||
1162 typeof(EntityRef<>).IsAssignableFrom(gtype) ||
1163 IsDeferredType(clrType.BaseType);
1167 private static MetaAccessor MakeMemberAccessor(Type accessorType, MemberInfo mi, MetaAccessor storage) {
1168 FieldInfo fi = mi as FieldInfo;
1169 MetaAccessor acc = null;
1171 acc = FieldAccessor.Create(accessorType, fi);
1174 PropertyInfo pi = (PropertyInfo)mi;
1175 acc = PropertyAccessor.Create(accessorType, pi, storage);
1179 [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
1180 private static void MakeDeferredAccessors(
1181 Type declaringType, MetaAccessor accessor,
1182 out MetaAccessor accessorValue, out MetaAccessor accessorDeferredValue, out MetaAccessor accessorDeferredSource
1184 if (accessor.Type.IsGenericType) {
1185 Type gtype = accessor.Type.GetGenericTypeDefinition();
1186 Type itemType = accessor.Type.GetGenericArguments()[0];
1187 if (gtype == typeof(Link<>)) {
1188 accessorValue = CreateAccessor(typeof(LinkValueAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1189 accessorDeferredValue = CreateAccessor(typeof(LinkDefValueAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1190 accessorDeferredSource = CreateAccessor(typeof(LinkDefSourceAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1193 else if (typeof(EntityRef<>).IsAssignableFrom(gtype)) {
1194 accessorValue = CreateAccessor(typeof(EntityRefValueAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1195 accessorDeferredValue = CreateAccessor(typeof(EntityRefDefValueAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1196 accessorDeferredSource = CreateAccessor(typeof(EntityRefDefSourceAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1199 else if (typeof(EntitySet<>).IsAssignableFrom(gtype)) {
1200 accessorValue = CreateAccessor(typeof(EntitySetValueAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1201 accessorDeferredValue = CreateAccessor(typeof(EntitySetDefValueAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1202 accessorDeferredSource = CreateAccessor(typeof(EntitySetDefSourceAccessor<,>).MakeGenericType(declaringType, itemType), accessor);
1206 throw Error.UnhandledDeferredStorageType(accessor.Type);
1208 private static MetaAccessor CreateAccessor(Type accessorType, params object[] args) {
1209 return (MetaAccessor)Activator.CreateInstance(accessorType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, args, null);
1213 internal class MappedAssociation : MetaAssociationImpl {
1214 MappedDataMember thisMember;
1215 MetaDataMember otherMember;
1217 ReadOnlyCollection<MetaDataMember> thisKey;
1218 ReadOnlyCollection<MetaDataMember> otherKey;
1222 bool thisKeyIsPrimaryKey;
1223 bool otherKeyIsPrimaryKey;
1224 AssociationMapping assocMap;
1226 internal MappedAssociation(MappedDataMember mm, AssociationMapping assocMap) {
1227 this.thisMember = mm;
1228 this.assocMap = assocMap;
1231 //validate the number of ThisKey columns is the same as the number of OtherKey columns
1232 if (this.thisKey.Count != this.otherKey.Count && this.thisKey.Count > 0 && this.otherKey.Count > 0) {
1233 throw Error.MismatchedThisKeyOtherKey(thisMember.Name, thisMember.DeclaringType.Name);
1236 #region Initialization
1237 private void Init() {
1238 this.isMany = TypeSystem.IsSequenceType(this.thisMember.Type);
1239 this.thisKey = (this.assocMap.ThisKey != null)
1240 ? MakeKeys(this.thisMember.DeclaringType, this.assocMap.ThisKey)
1241 : this.thisMember.DeclaringType.IdentityMembers;
1242 // this association refers to the parent if thisKey is not our own identity
1243 this.thisKeyIsPrimaryKey = AreEqual(this.thisKey, this.thisMember.DeclaringType.IdentityMembers);
1244 this.isForeignKey = this.assocMap.IsForeignKey;
1246 // if any key members are not nullable, the association is not nullable
1247 this.isNullable = true;
1248 foreach (MetaDataMember mm in this.thisKey) {
1250 throw Error.UnexpectedNull("MetaDataMember");
1252 if (!mm.CanBeNull) {
1253 this.isNullable = false;
1258 // validate DeleteOnNull specification
1259 if (assocMap.DeleteOnNull == true) {
1260 if (!(isForeignKey && !isMany && !isNullable)) {
1261 throw Error.InvalidDeleteOnNullSpecification(thisMember);
1265 private void InitOther() {
1266 if (this.otherType == null) {
1267 Type ot = this.isMany ? TypeSystem.GetElementType(this.thisMember.Type) : this.thisMember.Type;
1268 this.otherType = this.thisMember.DeclaringType.Model.GetMetaType(ot);
1269 System.Diagnostics.Debug.Assert(this.otherType.IsEntity);
1270 this.otherKey = (assocMap.OtherKey != null)
1271 ? MakeKeys(this.otherType, this.assocMap.OtherKey)
1272 : this.otherType.IdentityMembers;
1273 this.otherKeyIsPrimaryKey = AreEqual(this.otherKey, this.otherType.IdentityMembers);
1274 foreach (MetaDataMember omm in this.otherType.DataMembers) {
1275 if (omm.IsAssociation && omm != this.thisMember && omm.MappedName == this.thisMember.MappedName) {
1276 this.otherMember = omm;
1283 public override MetaDataMember ThisMember {
1284 get { return this.thisMember; }
1286 public override ReadOnlyCollection<MetaDataMember> ThisKey {
1287 get { return this.thisKey; }
1289 public override MetaDataMember OtherMember {
1290 get { return this.otherMember; }
1292 public override ReadOnlyCollection<MetaDataMember> OtherKey {
1293 get { return this.otherKey; }
1295 public override MetaType OtherType {
1296 get { return this.otherType; }
1298 public override bool IsMany {
1299 get { return this.isMany; }
1301 public override bool IsForeignKey {
1302 get { return this.isForeignKey; }
1304 public override bool IsUnique {
1305 get { return this.assocMap.IsUnique; }
1307 public override bool IsNullable {
1308 get { return this.isNullable; }
1310 public override bool ThisKeyIsPrimaryKey {
1311 get { return this.thisKeyIsPrimaryKey; }
1313 public override bool OtherKeyIsPrimaryKey {
1314 get { return this.otherKeyIsPrimaryKey; }
1316 public override string DeleteRule {
1318 return this.assocMap.DeleteRule;
1321 public override bool DeleteOnNull {
1323 return this.assocMap.DeleteOnNull;
1328 class MappedFunction : MetaFunction {
1330 FunctionMapping map;
1332 ReadOnlyCollection<MetaParameter> parameters;
1333 MetaParameter returnParameter;
1334 ReadOnlyCollection<MetaType> rowTypes;
1335 static ReadOnlyCollection<MetaParameter> _emptyParameters = new List<MetaParameter>(0).AsReadOnly();
1336 static ReadOnlyCollection<MetaType> _emptyTypes = new List<MetaType>(0).AsReadOnly();
1338 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // map parameter contains type names.
1339 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call.
1340 internal MappedFunction(MappedMetaModel model, FunctionMapping map, MethodInfo method) {
1343 this.method = method;
1344 this.rowTypes = _emptyTypes;
1346 if (map.Types.Count == 0 && this.method.ReturnType == typeof(IMultipleResults)) {
1347 throw Error.NoResultTypesDeclaredForFunction(method.Name);
1349 else if (map.Types.Count > 1 && this.method.ReturnType != typeof(IMultipleResults)) {
1350 throw Error.TooManyResultTypesDeclaredForFunction(method.Name);
1352 else if (map.Types.Count == 1 && this.method.ReturnType != typeof(IMultipleResults)) {
1353 Type elementType = TypeSystem.GetElementType(method.ReturnType);
1354 this.rowTypes = new List<MetaType>(1) { this.GetMetaType(map.Types[0], elementType) }.AsReadOnly();
1356 else if (map.Types.Count > 0) {
1357 List<MetaType> rowTypes = new List<MetaType>();
1358 foreach (TypeMapping rtm in map.Types) {
1359 Type elementType = model.FindType(rtm.Name);
1360 if (elementType == null) {
1361 throw Error.CouldNotFindElementTypeInModel(rtm.Name);
1363 MetaType mt = this.GetMetaType(rtm, elementType);
1364 // Only add unique meta types
1365 if (!rowTypes.Contains(mt)) {
1369 this.rowTypes = rowTypes.AsReadOnly();
1371 else if (map.FunReturn != null) {
1372 this.returnParameter = new MappedReturnParameter(method.ReturnParameter, map.FunReturn);
1376 ParameterInfo[] pis = this.method.GetParameters();
1377 if (pis.Length > 0) {
1378 List<MetaParameter> mps = new List<MetaParameter>(pis.Length);
1379 if (this.map.Parameters.Count != pis.Length) {
1380 throw Error.IncorrectNumberOfParametersMappedForMethod(this.map.MethodName);
1382 for (int i = 0; i < pis.Length; i++) {
1383 mps.Add(new MappedParameter(pis[i], this.map.Parameters[i]));
1385 this.parameters = mps.AsReadOnly();
1388 this.parameters = _emptyParameters;
1392 /// For the specified type, if it is a mapped type, use the Table
1393 /// metatype to get the correct inheritance metatype,
1394 /// otherwise create a new meta type.
1395 [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // Parameter contains various type references.
1396 [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // MappedRootType constructor call.
1397 private MetaType GetMetaType(TypeMapping tm, Type elementType) {
1398 MetaTable tbl = model.GetTable(elementType);
1400 return tbl.RowType.GetInheritanceType(elementType);
1402 return new MappedRootType((MappedMetaModel)model, null, tm, elementType);
1404 public override ReadOnlyCollection<MetaParameter> Parameters {
1405 get { return this.parameters; }
1407 public override string MappedName {
1408 get { return this.map.Name; }
1410 public override MethodInfo Method {
1411 get { return this.method; }
1413 public override MetaModel Model {
1414 get { return this.model; }
1416 public override string Name {
1417 get { return this.method.Name; }
1419 public override bool IsComposable {
1420 get { return this.map.IsComposable; }
1422 public override MetaParameter ReturnParameter {
1423 get { return this.returnParameter; }
1425 public override bool HasMultipleResults {
1426 get { return this.method.ReturnType == typeof(IMultipleResults); }
1428 public override ReadOnlyCollection<MetaType> ResultRowTypes {
1429 get { return this.rowTypes; }
1433 internal sealed class MappedParameter : MetaParameter {
1434 private ParameterInfo parameterInfo;
1435 private ParameterMapping map;
1437 public MappedParameter(ParameterInfo parameterInfo, ParameterMapping map) {
1438 this.parameterInfo = parameterInfo;
1441 public override ParameterInfo Parameter {
1442 get { return this.parameterInfo; }
1444 public override string Name {
1445 get { return this.parameterInfo.Name; }
1447 public override string MappedName {
1448 get { return this.map.Name; }
1450 public override Type ParameterType {
1451 get { return this.parameterInfo.ParameterType; }
1453 public override string DbType {
1454 get { return this.map.DbType; }
1458 internal sealed class MappedReturnParameter : MetaParameter {
1459 private ParameterInfo parameterInfo;
1460 private ReturnMapping map;
1462 public MappedReturnParameter(ParameterInfo parameterInfo, ReturnMapping map) {
1463 this.parameterInfo = parameterInfo;
1466 public override ParameterInfo Parameter {
1467 get { return this.parameterInfo; }
1469 public override string Name {
1470 get { return null; }
1472 public override string MappedName {
1473 get { return null; }
1475 public override Type ParameterType {
1476 get { return this.parameterInfo.ParameterType; }
1478 public override string DbType {
1479 get { return this.map.DbType; }
1483 internal abstract class MetaAssociationImpl : MetaAssociation {
1485 private static char[] keySeparators = new char[] { ',' };
1487 /// Given a MetaType and a set of key fields, return the set of MetaDataMembers
1488 /// corresponding to the key.
1490 protected static ReadOnlyCollection<MetaDataMember> MakeKeys(MetaType mtype, string keyFields) {
1491 string[] names = keyFields.Split(keySeparators);
1492 MetaDataMember[] members = new MetaDataMember[names.Length];
1493 for (int i = 0; i < names.Length; i++) {
1494 names[i] = names[i].Trim();
1495 MemberInfo[] rmis = mtype.Type.GetMember(names[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
1496 if (rmis == null || rmis.Length != 1) {
1497 throw Error.BadKeyMember(names[i], keyFields, mtype.Name);
1499 members[i] = mtype.GetDataMember(rmis[0]);
1500 if (members[i] == null) {
1501 throw Error.BadKeyMember(names[i], keyFields, mtype.Name);
1504 return new List<MetaDataMember>(members).AsReadOnly();
1508 /// Compare two sets of keys for equality.
1510 protected static bool AreEqual(IEnumerable<MetaDataMember> key1, IEnumerable<MetaDataMember> key2) {
1511 using (IEnumerator<MetaDataMember> e1 = key1.GetEnumerator()) {
1512 using (IEnumerator<MetaDataMember> e2 = key2.GetEnumerator()) {
1514 for (m1 = e1.MoveNext(), m2 = e2.MoveNext(); m1 && m2; m1 = e1.MoveNext(), m2 = e2.MoveNext()) {
1515 if (e1.Current != e2.Current)
1525 public override string ToString() {
1526 return string.Format(Globalization.CultureInfo.InvariantCulture, "{0} ->{1} {2}", ThisMember.DeclaringType.Name, IsMany ? "*" : "", OtherType.Name);
1530 internal sealed class UnmappedType : MetaType {
1533 Dictionary<object, MetaDataMember> dataMemberMap;
1534 ReadOnlyCollection<MetaDataMember> dataMembers;
1535 ReadOnlyCollection<MetaType> inheritanceTypes;
1536 object locktarget = new object(); // Hold locks on private object rather than public MetaType.
1538 private static ReadOnlyCollection<MetaType> _emptyTypes = new List<MetaType>().AsReadOnly();
1539 private static ReadOnlyCollection<MetaDataMember> _emptyDataMembers = new List<MetaDataMember>().AsReadOnly();
1540 private static ReadOnlyCollection<MetaAssociation> _emptyAssociations = new List<MetaAssociation>().AsReadOnly();
1542 internal UnmappedType(MetaModel model, Type type) {
1547 public override MetaModel Model {
1548 get { return this.model; }
1550 public override MetaTable Table {
1551 get { return null; }
1553 public override Type Type {
1554 get { return this.type; }
1556 public override string Name {
1557 get { return this.type.Name; }
1559 public override bool IsEntity {
1560 get { return false; }
1562 public override bool CanInstantiate {
1563 get { return !this.type.IsAbstract; }
1565 public override MetaDataMember DBGeneratedIdentityMember {
1566 get { return null; }
1568 public override MetaDataMember VersionMember {
1569 get { return null; }
1571 public override MetaDataMember Discriminator {
1572 get { return null; }
1574 public override bool HasUpdateCheck {
1575 get { return false; }
1577 public override ReadOnlyCollection<MetaType> InheritanceTypes {
1579 if (this.inheritanceTypes == null) {
1580 lock (this.locktarget) {
1581 if (this.inheritanceTypes == null) {
1582 this.inheritanceTypes = new MetaType[] { this }.ToList().AsReadOnly();
1586 return this.inheritanceTypes;
1589 public override MetaType GetInheritanceType(Type inheritanceType) {
1590 if (inheritanceType == this.type)
1594 public override ReadOnlyCollection<MetaType> DerivedTypes {
1595 get { return _emptyTypes; }
1597 public override MetaType GetTypeForInheritanceCode(object key) {
1600 public override bool HasInheritance {
1601 get { return false; }
1603 public override bool HasInheritanceCode {
1604 get { return false; }
1606 public override object InheritanceCode {
1607 get { return null; }
1609 public override MetaType InheritanceRoot {
1610 get { return this; }
1612 public override MetaType InheritanceBase {
1613 get { return null; }
1615 public override MetaType InheritanceDefault {
1616 get { return null; }
1618 public override bool IsInheritanceDefault {
1619 get { return false; }
1621 public override ReadOnlyCollection<MetaDataMember> DataMembers {
1623 this.InitDataMembers();
1624 return this.dataMembers;
1627 public override ReadOnlyCollection<MetaDataMember> PersistentDataMembers {
1628 get { return _emptyDataMembers; }
1630 public override ReadOnlyCollection<MetaDataMember> IdentityMembers {
1632 this.InitDataMembers();
1633 return this.dataMembers;
1636 public override ReadOnlyCollection<MetaAssociation> Associations {
1637 get { return _emptyAssociations; }
1639 public override MetaDataMember GetDataMember(MemberInfo mi) {
1641 throw Error.ArgumentNull("mi");
1642 this.InitDataMembers();
1643 if (this.dataMemberMap == null) {
1644 lock (this.locktarget) {
1645 if (this.dataMemberMap == null) {
1646 Dictionary<object, MetaDataMember> map = new Dictionary<object, MetaDataMember>();
1647 foreach (MetaDataMember mm in this.dataMembers) {
1648 map.Add(InheritanceRules.DistinguishedMemberName(mm.Member), mm);
1650 this.dataMemberMap = map;
1654 object dn = InheritanceRules.DistinguishedMemberName(mi);
1656 this.dataMemberMap.TryGetValue(dn, out mdm);
1660 private void InitDataMembers() {
1661 if (this.dataMembers == null) {
1662 lock (this.locktarget) {
1663 if (this.dataMembers == null) {
1664 List<MetaDataMember> dMembers = new List<MetaDataMember>();
1666 BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
1667 foreach (FieldInfo fi in this.type.GetFields(flags)) {
1668 MetaDataMember mm = new UnmappedDataMember(this, fi, ordinal);
1672 foreach (PropertyInfo pi in this.type.GetProperties(flags)) {
1673 MetaDataMember mm = new UnmappedDataMember(this, pi, ordinal);
1677 this.dataMembers = dMembers.AsReadOnly();
1683 public override string ToString() {
1687 public override MethodInfo OnLoadedMethod {
1688 get { return null; }
1691 public override MethodInfo OnValidateMethod {
1692 get { return null; }
1694 public override bool HasAnyValidateMethod {
1699 public override bool HasAnyLoadMethod {
1706 internal sealed class UnmappedDataMember : MetaDataMember {
1707 MetaType declaringType;
1711 MetaAccessor accPublic;
1712 object lockTarget = new object();
1714 internal UnmappedDataMember(MetaType declaringType, MemberInfo mi, int ordinal) {
1715 this.declaringType = declaringType;
1717 this.ordinal = ordinal;
1718 this.type = TypeSystem.GetMemberType(mi);
1720 private void InitAccessors() {
1721 if (this.accPublic == null) {
1722 lock (this.lockTarget) {
1723 if (this.accPublic == null) {
1724 this.accPublic = MakeMemberAccessor(this.member.ReflectedType, this.member);
1729 public override MetaType DeclaringType {
1730 get { return this.declaringType; }
1732 public override bool IsDeclaredBy(MetaType metaType) {
1733 if (metaType == null) {
1734 throw Error.ArgumentNull("metaType");
1736 return metaType.Type == this.member.DeclaringType;
1738 public override MemberInfo Member {
1739 get { return this.member; }
1741 public override MemberInfo StorageMember {
1742 get { return this.member; }
1744 public override string Name {
1745 get { return this.member.Name; }
1747 public override int Ordinal {
1748 get { return this.ordinal; }
1750 public override Type Type {
1751 get { return this.type; }
1753 public override MetaAccessor MemberAccessor {
1755 this.InitAccessors();
1756 return this.accPublic;
1759 public override MetaAccessor StorageAccessor {
1761 this.InitAccessors();
1762 return this.accPublic;
1765 public override MetaAccessor DeferredValueAccessor {
1766 get { return null; }
1768 public override MetaAccessor DeferredSourceAccessor {
1769 get { return null; }
1771 public override bool IsDeferred {
1772 get { return false; }
1774 public override bool IsPersistent {
1775 get { return false; }
1777 public override bool IsAssociation {
1778 get { return false; }
1780 public override bool IsPrimaryKey {
1781 get { return false; }
1783 public override bool IsDbGenerated {
1784 get { return false; }
1786 public override bool IsVersion {
1787 get { return false; }
1789 public override bool IsDiscriminator {
1790 get { return false; }
1792 public override bool CanBeNull {
1793 get { return !this.type.IsValueType || TypeSystem.IsNullableType(this.type); }
1795 public override string DbType {
1796 get { return null; }
1798 public override string Expression {
1799 get { return null; }
1801 public override string MappedName {
1802 get { return this.member.Name; }
1804 public override UpdateCheck UpdateCheck {
1805 get { return UpdateCheck.Never; }
1807 public override AutoSync AutoSync {
1808 get { return AutoSync.Never; }
1810 public override MetaAssociation Association {
1811 get { return null; }
1813 public override MethodInfo LoadMethod {
1814 get { return null; }
1816 private static MetaAccessor MakeMemberAccessor(Type accessorType, MemberInfo mi) {
1817 FieldInfo fi = mi as FieldInfo;
1818 MetaAccessor acc = null;
1820 acc = FieldAccessor.Create(accessorType, fi);
1823 PropertyInfo pi = (PropertyInfo)mi;
1824 acc = PropertyAccessor.Create(accessorType, pi, null);