PageRenderTime 3ms CodeModel.GetById 18ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 1ms

/mcs/class/System.Data.Linq/src/DbLinq/Data/Linq/Mapping/AttributedMetaModel.cs

https://github.com/ztfuqingvip/mono
C# | 259 lines | 136 code | 28 blank | 95 comment | 26 complexity | 9d60312ca7e72be8265c86e945c14fe6 MD5 | raw file
  1#region MIT license
  2// 
  3// MIT license
  4//
  5// Copyright (c) 2007-2008 Jiri Moudry, Stefan Klinger
  6// 
  7// Permission is hereby granted, free of charge, to any person obtaining a copy
  8// of this software and associated documentation files (the "Software"), to deal
  9// in the Software without restriction, including without limitation the rights
 10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11// copies of the Software, and to permit persons to whom the Software is
 12// furnished to do so, subject to the following conditions:
 13// 
 14// The above copyright notice and this permission notice shall be included in
 15// all copies or substantial portions of the Software.
 16// 
 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23// THE SOFTWARE.
 24// 
 25#endregion
 26
 27using System;
 28using System.Collections.Generic;
 29using System.Data.Linq.Mapping;
 30using System.Diagnostics;
 31using System.Linq;
 32using System.Reflection;
 33
 34#if MONO_STRICT
 35using System.Data.Linq;
 36#else
 37using DbLinq.Data.Linq;
 38#endif
 39
 40using DbLinq.Data.Linq.Mapping;
 41using DbLinq.Util;
 42
 43//Change notes:
 44//removed virtual init call from constructor
 45//renamed member variables to be better distinguishable from local variables
 46
 47namespace DbLinq.Data.Linq.Mapping
 48{
 49    /// <summary>
 50    /// This class is a stateless attribute meta model (it does not depend on any provider)
 51    /// So the MappingSource can use singletons
 52    /// </summary>
 53    [DebuggerDisplay("MetaModel for {DatabaseName}")]
 54    internal class AttributedMetaModel : MetaModel
 55	{
 56		private readonly Type _ContextType;
 57
 58		/// <summary>
 59		/// The DataContext (or a derived type) that is used for this model.
 60		/// </summary>
 61		public override Type ContextType
 62		{
 63			get { return _ContextType; }
 64		}
 65
 66
 67		// just because of this, the whole model can not be cached efficiently, since we can not guarantee
 68		// that another mapping source instance will not use the same model
 69		private MappingSource _MappingSource;
 70
 71		/// <summary>
 72		/// The mapping source used for that model.
 73		/// </summary>
 74		public override MappingSource MappingSource
 75		{
 76			get { return _MappingSource; }
 77		}
 78
 79
 80		private string _DatabaseName;
 81
 82		/// <summary>
 83		/// Name of the database.
 84		/// </summary>
 85		/// <remarks>
 86		/// The name of the database is the type name of the DataContext inheriting class.
 87		/// If a plain DataContext is used, the database name is "DataContext".
 88		/// </remarks>
 89		public override string DatabaseName
 90		{
 91			get {
 92                if (_DatabaseName == null)
 93                    DiscoverDatabaseName();
 94                return _DatabaseName;
 95            }
 96		}
 97
 98
 99		//Currently not implemented Properties
100		public override Type ProviderType
101		{
102			get { throw new NotImplementedException(); }
103		}
104
105		//This function will try to add unknown table types
106		private IDictionary<Type, MetaTable> _Tables = new Dictionary<Type, MetaTable>();
107
108		/// <summary>
109		/// Initializes a new instance of the <see cref="AttributedMetaModel"/> class.
110		/// </summary>
111		/// <param name="contextType">DataContext type used.</param>
112		/// <param name="mappingSource">The mapping source.</param>
113        public AttributedMetaModel(Type contextType, MappingSource mappingSource)
114        {
115            _ContextType = contextType;
116            _MappingSource = mappingSource;
117        }
118
119		/// <summary>
120		/// Gets the <see cref="MetaFunction"/> for the given MethodInfo.
121		/// </summary>
122		/// <param name="method">The method info for which the <see cref="MetaFunction"/> should be returned.</param>
123        public override MetaFunction GetFunction(MethodInfo method)
124        {
125            return GetFunctions().SingleOrDefault(m => m.Method == method);
126        }
127
128		/// <summary>
129		/// Returns an enumeration of all mapped functions.
130		/// </summary>
131        public override IEnumerable<MetaFunction> GetFunctions()
132        {
133            const BindingFlags scope = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
134            foreach (var methodInfo in _ContextType.GetMethods(scope))
135            {
136                var function = methodInfo.GetAttribute<FunctionAttribute>();
137                if (function != null)
138                    yield return new AttributedMetaFunction(methodInfo, function);
139            }
140        }
141
142        public override MetaType GetMetaType(Type type)
143        {
144            var metaTable = GetTable(type);
145            if (metaTable == null)
146                return null;
147            return metaTable.RowType;
148        }
149
150		/// <summary>
151		/// Returns the <see cref="MetaTable"/> for the given table type.
152		/// </summary>
153		/// <remarks>
154		/// If the given type is not allready mapped it tries to map it.
155		/// </remarks>
156		/// <param name="tableType"><see cref="MetaTable"/> for the table type or null if not mappable.</param>
157		public override MetaTable GetTable(Type tableType)
158		{
159			MetaTable metaTable;
160			_Tables.TryGetValue(tableType, out metaTable);
161			if (metaTable != null)
162			{
163				return metaTable;
164			}
165			return GetTables().FirstOrDefault(t => t.RowType.Type == tableType)
166				?? AddTableType(tableType);
167		}
168
169		/// <summary>
170		/// Returns an enumeration of all mapped tables.
171		/// </summary>
172        //Discover all the tables used with this context, used for the GetTable/GetTables function
173        //Behaviour of GetTables in the Framework: STRANGE
174        //If the DataContext was a strong typed one (derived with fields for the tables),
175        //it returns a list of MetaTables for all this tables.
176        //But if you call GetTable<T> with an additional table - the table doesn't get added to this list.
177        //If you use a vanilla DataContext the list is empty at the beginning (ok no surprise here),
178        //if you call GetTable<T> here the table is added to the list.
179        //
180        //If you add to properties with the same T of Table<T> only the first gets into the list.
181        public override IEnumerable<MetaTable> GetTables()
182        {
183            const BindingFlags scope = BindingFlags.GetField |
184                BindingFlags.GetProperty | BindingFlags.Static |
185                BindingFlags.Instance | BindingFlags.NonPublic |
186                BindingFlags.Public;
187            var seen = new HashSet<Type>();
188            foreach (var info in _ContextType.GetMembers(scope))
189            {
190                // Only look for Fields & Properties.
191                if (info.MemberType != MemberTypes.Field && info.MemberType != MemberTypes.Property)
192                    continue;
193                Type memberType = info.GetMemberType();
194
195                if (memberType == null || !memberType.IsGenericType ||
196                        memberType.GetGenericTypeDefinition() != typeof(Table<>))
197                    continue;
198                var tableType = memberType.GetGenericArguments()[0];
199                if (tableType.IsGenericParameter)
200                    continue;
201                if (seen.Contains(tableType))
202                    continue;
203                seen.Add(tableType);
204
205                MetaTable metaTable;
206                if (_Tables.TryGetValue(tableType, out metaTable))
207                  yield return metaTable;
208                else
209                  yield return AddTableType(tableType);
210            }
211        }
212
213		/// <summary>
214		/// Tries to discover the name of the database.
215		/// Database name == class name of the DataContext's most derived class used for this MetaModel.
216		/// </summary>
217		private void DiscoverDatabaseName()
218		{
219			var databaseAttribute = _ContextType.GetAttribute<DatabaseAttribute>();
220			if (databaseAttribute != null)
221			{
222				_DatabaseName = databaseAttribute.Name;
223			}
224			else //Found no DatabaseAttribute get the class name
225			{
226				_DatabaseName = _ContextType.Name;
227			}
228		}
229
230		/// <summary>
231		/// Adds the table of the given type to the mappings.
232		/// </summary>
233		/// <remarks>
234		/// The given type must have a <see cref="TableAttribute" /> to be mappable.
235		/// </remarks>
236		/// <param name="tableType">Type of the table.</param>
237		/// <returns>
238		/// Returns the <see cref="MetaTable"/> for the given table type or null if it is not mappable.
239		/// </returns>
240		private MetaTable AddTableType(Type tableType)
241		{
242			//No need to check base types because framework implementation doesn't do this either
243			var tableAttribute = tableType.GetAttribute<TableAttribute>();
244
245			if (tableAttribute == null)
246			{
247				return null;
248			}
249
250			//First set up the table without associations
251			var metaType = new AttributedMetaType(tableType);
252			var metaTable = new AttributedMetaTable(tableAttribute, metaType, this);
253			metaType.SetMetaTable(metaTable);
254			_Tables[tableType] = metaTable;
255
256			return metaTable;
257		}
258	}
259}