From e2901b988cecca362331cc7223cd2514d85c5c98 Mon Sep 17 00:00:00 2001 From: Frans Bouma Date: Tue, 23 Dec 2014 16:52:20 +0100 Subject: [PATCH] Moved files to their own folders --- .../AttributedMetaModel.cs | 271 ++++++++++++++ .../MappedMetaModel/MappedMetaModel.cs | 346 ++++++++++++++++++ src/Mapping/MappingSource/MappingSource.cs | 94 +++++ src/Mapping/MetaModel/MetaModel.cs | 70 ++++ 4 files changed, 781 insertions(+) create mode 100644 src/Mapping/AttributedMetaModel/AttributedMetaModel.cs create mode 100644 src/Mapping/MappedMetaModel/MappedMetaModel.cs create mode 100644 src/Mapping/MappingSource/MappingSource.cs create mode 100644 src/Mapping/MetaModel/MetaModel.cs diff --git a/src/Mapping/AttributedMetaModel/AttributedMetaModel.cs b/src/Mapping/AttributedMetaModel/AttributedMetaModel.cs new file mode 100644 index 0000000..c4bdde9 --- /dev/null +++ b/src/Mapping/AttributedMetaModel/AttributedMetaModel.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Linq; +using System.Data.Linq.Provider; +using System.Data.Linq.SqlClient; +using System.Threading; +using LinqToSqlShared.Mapping; +using System.Runtime.CompilerServices; + +namespace System.Data.Linq.Mapping { + + internal class AttributedMetaModel : MetaModel { + ReaderWriterLock _lock = new ReaderWriterLock(); + MappingSource mappingSource; + Type contextType; + Type providerType; + Dictionary metaTypes; + Dictionary metaTables; + ReadOnlyCollection staticTables; + Dictionary metaFunctions; + string dbName; + bool initStaticTables; + bool initFunctions; + + internal AttributedMetaModel(MappingSource mappingSource, Type contextType) { + this.mappingSource = mappingSource; + this.contextType = contextType; + this.metaTypes = new Dictionary(); + this.metaTables = new Dictionary(); + this.metaFunctions = new Dictionary(); + + // Provider type + ProviderAttribute[] attrs = (ProviderAttribute[])this.contextType.GetCustomAttributes(typeof(ProviderAttribute), true); + if (attrs != null && attrs.Length == 1) { // Provider attribute is !AllowMultiple + this.providerType = attrs[0].Type; + } else { + this.providerType = typeof(SqlProvider); + } + + // Database name + DatabaseAttribute[] das = (DatabaseAttribute[])this.contextType.GetCustomAttributes(typeof(DatabaseAttribute), false); + this.dbName = (das != null && das.Length > 0) ? das[0].Name : this.contextType.Name; + } + + public override MappingSource MappingSource { + get { return this.mappingSource; } + } + + public override Type ContextType { + get { return this.contextType; } + } + + public override string DatabaseName { + get { return this.dbName; } + } + + public override Type ProviderType { + get { return this.providerType; } + } + + public override IEnumerable GetTables() { + this.InitStaticTables(); + if (this.staticTables.Count > 0) { + return this.staticTables; + } + else { + _lock.AcquireReaderLock(Timeout.Infinite); + try { + return this.metaTables.Values.Where(x => x != null).Distinct(); + } + finally { + _lock.ReleaseReaderLock(); + } + } + } + #region Initialization + private void InitStaticTables() { + if (!this.initStaticTables) { + _lock.AcquireWriterLock(Timeout.Infinite); + try { + if (!this.initStaticTables) { + HashSet tables = new HashSet(); + for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) { + FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + foreach (FieldInfo fi in fields) { + Type ft = fi.FieldType; + if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Table<>)) { + Type rowType = ft.GetGenericArguments()[0]; + tables.Add(this.GetTableNoLocks(rowType)); + } + } + PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + foreach (PropertyInfo pi in props) { + Type pt = pi.PropertyType; + if (pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Table<>)) { + Type rowType = pt.GetGenericArguments()[0]; + tables.Add(this.GetTableNoLocks(rowType)); + } + } + } + this.staticTables = new List(tables).AsReadOnly(); + this.initStaticTables = true; + } + } + finally { + _lock.ReleaseWriterLock(); + } + } + } + + private void InitFunctions() { + if (!this.initFunctions) { + _lock.AcquireWriterLock(Timeout.Infinite); + try { + if (!this.initFunctions) { + if (this.contextType != typeof(DataContext)) { + for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) { + foreach (MethodInfo mi in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { + if (IsUserFunction(mi)) { + if (mi.IsGenericMethodDefinition) { + // Added this constraint because XML mapping model didn't support mapping sprocs to generic method. + // The attribute mapping model was, however, able to support it. This check is for parity between + // the two models. + throw Error.InvalidUseOfGenericMethodAsMappedFunction(mi.Name); + } + MetaPosition mp = new MetaPosition(mi); + if (!this.metaFunctions.ContainsKey(mp)) { + MetaFunction metaFunction = new AttributedMetaFunction(this, mi); + this.metaFunctions.Add(mp, metaFunction); + + // pre-set all known function result types into metaType map + foreach (MetaType rt in metaFunction.ResultRowTypes) { + foreach (MetaType it in rt.InheritanceTypes) { + if (!this.metaTypes.ContainsKey(it.Type)) { + this.metaTypes.Add(it.Type, it); + } + } + } + } + } + } + } + } + this.initFunctions = true; + } + } + finally { + _lock.ReleaseWriterLock(); + } + } + } + + private static bool IsUserFunction(MethodInfo mi) { + return Attribute.GetCustomAttribute(mi, typeof(FunctionAttribute), false) != null; + } + #endregion + + public override MetaTable GetTable(Type rowType) { + if (rowType == null) { + throw Error.ArgumentNull("rowType"); + } + MetaTable table; + _lock.AcquireReaderLock(Timeout.Infinite); + try { + if (this.metaTables.TryGetValue(rowType, out table)) { + return table; + } + } + finally { + _lock.ReleaseReaderLock(); + } + _lock.AcquireWriterLock(Timeout.Infinite); + try { + table = this.GetTableNoLocks(rowType); + } + finally { + _lock.ReleaseWriterLock(); + } + return table; + } + + internal MetaTable GetTableNoLocks(Type rowType) { + MetaTable table; + if (!this.metaTables.TryGetValue(rowType, out table)) { + Type root = GetRoot(rowType) ?? rowType; + TableAttribute[] attrs = (TableAttribute[])root.GetCustomAttributes(typeof(TableAttribute), true); + if (attrs.Length == 0) { + this.metaTables.Add(rowType, null); + } + else { + if (!this.metaTables.TryGetValue(root, out table)) { + table = new AttributedMetaTable(this, attrs[0], root); + foreach (MetaType mt in table.RowType.InheritanceTypes) { + this.metaTables.Add(mt.Type, table); + } + } + // catch case of derived type that is not part of inheritance + if (table.RowType.GetInheritanceType(rowType) == null) { + this.metaTables.Add(rowType, null); + return null; + } + } + } + return table; + } + + private static Type GetRoot(Type derivedType) { + while (derivedType != null && derivedType != typeof(object)) { + TableAttribute[] attrs = (TableAttribute[])derivedType.GetCustomAttributes(typeof(TableAttribute), false); + if (attrs.Length > 0) + return derivedType; + derivedType = derivedType.BaseType; + } + return null; + } + + public override MetaType GetMetaType(Type type) { + if (type == null) { + throw Error.ArgumentNull("type"); + } + MetaType mtype = null; + _lock.AcquireReaderLock(Timeout.Infinite); + try { + if (this.metaTypes.TryGetValue(type, out mtype)) { + return mtype; + } + } + finally { + _lock.ReleaseReaderLock(); + } + // Attributed meta model allows us to learn about tables we did not + // statically know about + MetaTable tab = this.GetTable(type); + if (tab != null) { + return tab.RowType.GetInheritanceType(type); + } + this.InitFunctions(); + _lock.AcquireWriterLock(Timeout.Infinite); + try { + if (!this.metaTypes.TryGetValue(type, out mtype)) { + mtype = new UnmappedType(this, type); + this.metaTypes.Add(type, mtype); + } + } + finally { + _lock.ReleaseWriterLock(); + } + return mtype; + } + + public override MetaFunction GetFunction(MethodInfo method) { + if (method == null) { + throw Error.ArgumentNull("method"); + } + this.InitFunctions(); + MetaFunction function = null; + this.metaFunctions.TryGetValue(new MetaPosition(method), out function); + return function; + } + + public override IEnumerable GetFunctions() { + this.InitFunctions(); + return this.metaFunctions.Values.ToList().AsReadOnly(); + } + } +} \ No newline at end of file diff --git a/src/Mapping/MappedMetaModel/MappedMetaModel.cs b/src/Mapping/MappedMetaModel/MappedMetaModel.cs new file mode 100644 index 0000000..0bd0319 --- /dev/null +++ b/src/Mapping/MappedMetaModel/MappedMetaModel.cs @@ -0,0 +1,346 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Linq; +using System.Data.Linq.Provider; +using System.Data.Linq.Mapping; +using System.Data.Linq.SqlClient; +using System.Threading; +using System.Runtime.Versioning; +using LinqToSqlShared.Mapping; +using System.Runtime.CompilerServices; + +namespace System.Data.Linq.Mapping { + + internal class MappedMetaModel : MetaModel { + ReaderWriterLock @lock = new ReaderWriterLock(); + MappingSource mappingSource; + Type contextType; + Type providerType; + DatabaseMapping mapping; + HashSet modules; + Dictionary types; + Dictionary metaTypes; + Dictionary metaTables; + Dictionary metaFunctions; + bool fullyLoaded; + + [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // mapping parameter contains various type references. + [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call. + internal MappedMetaModel(MappingSource mappingSource, Type contextType, DatabaseMapping mapping) { + this.mappingSource = mappingSource; + this.contextType = contextType; + this.mapping = mapping; + this.modules = new HashSet(); + this.modules.Add(this.contextType.Module); + this.metaTypes = new Dictionary(); + this.metaTables = new Dictionary(); + this.types = new Dictionary(); + // Provider type + if (this.providerType == null && !String.IsNullOrEmpty(this.mapping.Provider)) { + this.providerType = this.FindType(this.mapping.Provider, typeof(SqlProvider).Namespace); + if (this.providerType == null) { + throw Error.ProviderTypeNotFound(this.mapping.Provider); + } + } + else if (this.providerType == null) { + this.providerType = typeof(SqlProvider); + } + this.Init(); + } + #region Initialization + private void Init() { + if (!fullyLoaded) { + // The fullyLoaded state is required so that tools like + // CreateDatabase can get a full view of all tables. + @lock.AcquireWriterLock(Timeout.Infinite); + try { + if (!fullyLoaded) { + // Initialize static tables and functions. + this.InitStaticTables(); + this.InitFunctions(); + fullyLoaded = true; + } + } + finally { + @lock.ReleaseWriterLock(); + } + } + } + + [ResourceExposure(ResourceScope.None)] // Exposure is via external mapping file/attributes. + [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine, ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call. + private void InitStaticTables() { + this.InitStaticTableTypes(); + foreach (TableMapping tableMapping in this.mapping.Tables) { + Type rowType = this.FindType(tableMapping.RowType.Name); + if (rowType == null) { + throw Error.CouldNotFindTypeFromMapping(tableMapping.RowType.Name); + } + Type rootType = this.GetRootType(rowType, tableMapping.RowType); + MetaTable table = new MappedTable(this, tableMapping, rootType); + foreach (MetaType mt in table.RowType.InheritanceTypes) { + this.metaTypes.Add(mt.Type, mt); + this.metaTables.Add(mt.Type, table); + } + } + } + + private void InitStaticTableTypes() { + for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) { + FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + foreach (FieldInfo fi in fields) { + Type ft = fi.FieldType; + if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Table<>)) { + Type rowType = ft.GetGenericArguments()[0]; + if (!this.types.ContainsKey(rowType.Name)) { + this.types.Add(rowType.FullName, rowType); + if (!this.types.ContainsKey(rowType.Name)) { + this.types.Add(rowType.Name, rowType); + } + this.modules.Add(rowType.Module); + } + } + } + PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + foreach (PropertyInfo pi in props) { + Type pt = pi.PropertyType; + if (pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Table<>)) { + Type rowType = pt.GetGenericArguments()[0]; + if (!this.types.ContainsKey(rowType.Name)) { + this.types.Add(rowType.FullName, rowType); + if (!this.types.ContainsKey(rowType.Name)) { + this.types.Add(rowType.Name, rowType); + } + this.modules.Add(rowType.Module); + } + } + } + } + } + + [ResourceExposure(ResourceScope.None)] // mapping instance variable is set elsewhere. + [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine, ResourceScope.Assembly | ResourceScope.Machine)] // For GetMethods call. + private void InitFunctions() { + this.metaFunctions = new Dictionary(); + if (this.contextType != typeof(DataContext)) { + foreach (FunctionMapping fmap in this.mapping.Functions) { + MethodInfo method = this.GetMethod(fmap.MethodName); + if (method == null) { + throw Error.MethodCannotBeFound(fmap.MethodName); + } + MappedFunction func = new MappedFunction(this, fmap, method); + this.metaFunctions.Add(new MetaPosition(method), func); + + // pre-set all known function result types into metaType map + foreach (MetaType rt in func.ResultRowTypes) { + foreach (MetaType it in rt.InheritanceTypes) { + if (!this.metaTypes.ContainsKey(it.Type)) { + this.metaTypes.Add(it.Type, it); + } + } + } + } + } + } + #endregion + + public override MappingSource MappingSource { + get { return this.mappingSource; } + } + + public override Type ContextType { + get { return this.contextType; } + } + + public override string DatabaseName { + get { return this.mapping.DatabaseName; } + } + + public override Type ProviderType { + get { return this.providerType; } + } + + public override IEnumerable GetTables() { + return this.metaTables.Values.Where(x => x != null).Distinct(); + } + + public override MetaTable GetTable(Type rowType) { + if (rowType == null) { + throw Error.ArgumentNull("rowType"); + } + MetaTable table = null; + this.metaTables.TryGetValue(rowType, out table); + return table; + } + + public override MetaType GetMetaType(Type type) { + if (type == null) { + throw Error.ArgumentNull("type"); + } + MetaType mtype = null; + @lock.AcquireReaderLock(Timeout.Infinite); + try { + if (this.metaTypes.TryGetValue(type, out mtype)) { + return mtype; + } + } + finally { + @lock.ReleaseReaderLock(); + } + @lock.AcquireWriterLock(Timeout.Infinite); + try { + if (!this.metaTypes.TryGetValue(type, out mtype)) { + // not known, so must be unmapped type + mtype = new UnmappedType(this, type); + this.metaTypes.Add(type, mtype); + } + } + finally { + @lock.ReleaseWriterLock(); + } + return mtype; + } + + public override MetaFunction GetFunction(MethodInfo method) { + if (method == null) { + throw new ArgumentNullException("method"); + } + MetaFunction func = null; + this.metaFunctions.TryGetValue(new MetaPosition(method), out func); + return func; + } + + public override IEnumerable GetFunctions() { + return this.metaFunctions.Values; + } + + private Type GetRootType(Type type, TypeMapping rootMapping) { + if (string.Compare(rootMapping.Name, type.Name, StringComparison.Ordinal) == 0 + || string.Compare(rootMapping.Name, type.FullName, StringComparison.Ordinal) == 0 + || string.Compare(rootMapping.Name, type.AssemblyQualifiedName, StringComparison.Ordinal) == 0) + return type; + if (type.BaseType != typeof(object)) { + return this.GetRootType(type.BaseType, rootMapping); + } + throw Error.UnableToResolveRootForType(type); + } + + [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter will be found on a type. + [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call. + private MethodInfo GetMethod(string name) { + string typeName, methodName; + this.GetTypeAndMethod(name, out typeName, out methodName); + Type type = this.FindType(typeName); + if (type != null) { + return type.GetMethod(methodName, BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); + } + return null; + } + + private void GetTypeAndMethod(string name, out string typeName, out string methodName) { + int dotIndex = name.LastIndexOf(".", StringComparison.CurrentCulture); + if (dotIndex > 0) { + typeName = name.Substring(0, dotIndex); + methodName = name.Substring(dotIndex + 1); + } + else { + typeName = this.contextType.FullName; + methodName = name; + } + } + + [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter is a type name. + [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // FindType method call. + internal Type FindType(string name) { + return this.FindType(name, this.contextType.Namespace); + } + + [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter is a type name. + [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // SearchForType method call. + internal Type FindType(string name, string defaultNamespace) { + Type result = null; + string name2 = null; + @lock.AcquireReaderLock(Timeout.Infinite); + try { + if (this.types.TryGetValue(name, out result)) { + return result; + } + name2 = name.Contains(".") ? null : defaultNamespace + "." + name; + if (name2 != null && this.types.TryGetValue(name2, out result)) { + return result; + } + } + finally { + @lock.ReleaseReaderLock(); + } + // don't block anyone while we search for the correct type + Type foundResult = this.SearchForType(name); + + if (foundResult == null && name2 != null) { + foundResult = this.SearchForType(name2); + } + if (foundResult != null) { + @lock.AcquireWriterLock(Timeout.Infinite); + try { + if (this.types.TryGetValue(name, out result)) { + return result; + } + this.types.Add(name, foundResult); + return foundResult; + } + finally { + @lock.ReleaseWriterLock(); + } + } + return null; + } + + [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter is a type name. + [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // SearchForType method call. + private Type SearchForType(string name) { + // Try search for type using case sensitive. + Type type = SearchForType(name, false); + if (type != null) { + return type; + } + + // Try search for type using case in-sensitive. + return SearchForType(name, true); + } + + [ResourceExposure(ResourceScope.Assembly | ResourceScope.Machine)] // name parameter is a type name. + [ResourceConsumption(ResourceScope.Assembly | ResourceScope.Machine)] // Assembly.GetLoadedModules method call. + private Type SearchForType(string name, bool ignoreCase) { + // first try default system lookup + Type type = Type.GetType(name, false, ignoreCase); + if (type != null) { + return type; + } + + // try all known modules (modules that other statically known types were found in) + foreach (Module module in this.modules) { + type = module.GetType(name, false, ignoreCase); + if (type != null) { + return type; + } + } + + // try all loaded modules (is there a better way?) + foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { + foreach (Module module in a.GetLoadedModules()) { + type = module.GetType(name, false, ignoreCase); + if (type != null) { + return type; + } + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Mapping/MappingSource/MappingSource.cs b/src/Mapping/MappingSource/MappingSource.cs new file mode 100644 index 0000000..6ae4bd0 --- /dev/null +++ b/src/Mapping/MappingSource/MappingSource.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Linq; +using System.Reflection; +using System.Runtime.Versioning; +using System.Text; +using System.Threading; +using System.Xml; +using System.Xml.Serialization; +using LinqToSqlShared.Mapping; + +namespace System.Data.Linq.Mapping { + using System.Data.Linq.Provider; + using System.Diagnostics.CodeAnalysis; + + /// + /// Represents a source for mapping information. + /// + public abstract class MappingSource { + MetaModel primaryModel; + ReaderWriterLock rwlock; + Dictionary secondaryModels; + + /// + /// Gets the MetaModel representing a DataContext and all it's + /// accessible tables, functions and entities. + /// + public MetaModel GetModel(Type dataContextType) { + if (dataContextType == null) { + throw Error.ArgumentNull("dataContextType"); + } + MetaModel model = null; + if (this.primaryModel == null) { + model = this.CreateModel(dataContextType); + Interlocked.CompareExchange(ref this.primaryModel, model, null); + } + + // if the primary one matches, use it! + if (this.primaryModel.ContextType == dataContextType) { + return this.primaryModel; + } + + // the rest of this only happens if you are using the mapping source for + // more than one context type + + // build a map if one is not already defined + if (this.secondaryModels == null) { + Interlocked.CompareExchange>(ref this.secondaryModels, new Dictionary(), null); + } + + // if we haven't created a read/writer lock, make one now + if (this.rwlock == null) { + Interlocked.CompareExchange(ref this.rwlock, new ReaderWriterLock(), null); + } + + // lock the map and look inside + MetaModel foundModel; + this.rwlock.AcquireReaderLock(Timeout.Infinite); + try { + if (this.secondaryModels.TryGetValue(dataContextType, out foundModel)) { + return foundModel; + } + } + finally { + this.rwlock.ReleaseReaderLock(); + } + // if it wasn't found, lock for write and try again + this.rwlock.AcquireWriterLock(Timeout.Infinite); + try { + if (this.secondaryModels.TryGetValue(dataContextType, out foundModel)) { + return foundModel; + } + if (model == null) { + model = this.CreateModel(dataContextType); + } + this.secondaryModels.Add(dataContextType, model); + } + finally { + this.rwlock.ReleaseWriterLock(); + } + return model; + } + + /// + /// Creates a new instance of a MetaModel. This method is called by GetModel(). + /// Override this method when defining a new type of MappingSource. + /// + /// + /// + protected abstract MetaModel CreateModel(Type dataContextType); + } +} \ No newline at end of file diff --git a/src/Mapping/MetaModel/MetaModel.cs b/src/Mapping/MetaModel/MetaModel.cs new file mode 100644 index 0000000..a9488c4 --- /dev/null +++ b/src/Mapping/MetaModel/MetaModel.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Linq; +using System.Diagnostics.CodeAnalysis; + +namespace System.Data.Linq.Mapping { + /// + /// A MetaModel is an abstraction representing the mapping between a database and domain objects + /// + public abstract class MetaModel { + /// + /// The mapping source that originated this model. + /// + public abstract MappingSource MappingSource { get; } + /// + /// The type of DataContext type this model describes. + /// + public abstract Type ContextType { get; } + /// + /// The name of the database. + /// + public abstract string DatabaseName { get; } + /// + /// The CLR type that implements IProvider to use as a provider. + /// + public abstract Type ProviderType { get; } + /// + /// Gets the MetaTable associated with a given type. + /// + /// The CLR row type. + /// The MetaTable if one exists, otherwise null. + public abstract MetaTable GetTable(Type rowType); + /// + /// Gets the MetaFunction corresponding to a database function: user-defined function, table-valued function or stored-procedure. + /// + /// The method defined on the DataContext or subordinate class that represents the database function. + /// The MetaFunction if one exists, otherwise null. + public abstract MetaFunction GetFunction(MethodInfo method); + /// + /// Get an enumeration of all tables. + /// + /// An enumeration of all the MetaTables + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Non-trivial operations are not suitable for properties.")] + public abstract IEnumerable GetTables(); + /// + /// Get an enumeration of all functions. + /// + /// An enumeration of all the MetaFunctions + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Non-trivial operations are not suitable for properties.")] + public abstract IEnumerable GetFunctions(); + /// + /// This method discovers the MetaType for the given Type. + /// + public abstract MetaType GetMetaType(Type type); + /// + /// Internal value used to determine a reference identity for comparing meta models + /// without needing to keep track of the actual meta model reference. + /// + private object identity = new object(); + internal object Identity { + get { return this.identity; } + } + } +}