PageRenderTime 50ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/tools/sqlmetal/src/DbLinq/Data/Linq/Mapping/AttributedMetaModel.cs

http://github.com/mono/mono
C# | 259 lines | 136 code | 28 blank | 95 comment | 26 complexity | 9d60312ca7e72be8265c86e945c14fe6 MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Unlicense, Apache-2.0
  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. using System;
  27. using System.Collections.Generic;
  28. using System.Data.Linq.Mapping;
  29. using System.Diagnostics;
  30. using System.Linq;
  31. using System.Reflection;
  32. #if MONO_STRICT
  33. using System.Data.Linq;
  34. #else
  35. using DbLinq.Data.Linq;
  36. #endif
  37. using DbLinq.Data.Linq.Mapping;
  38. using DbLinq.Util;
  39. //Change notes:
  40. //removed virtual init call from constructor
  41. //renamed member variables to be better distinguishable from local variables
  42. namespace DbLinq.Data.Linq.Mapping
  43. {
  44. /// <summary>
  45. /// This class is a stateless attribute meta model (it does not depend on any provider)
  46. /// So the MappingSource can use singletons
  47. /// </summary>
  48. [DebuggerDisplay("MetaModel for {DatabaseName}")]
  49. internal class AttributedMetaModel : MetaModel
  50. {
  51. private readonly Type _ContextType;
  52. /// <summary>
  53. /// The DataContext (or a derived type) that is used for this model.
  54. /// </summary>
  55. public override Type ContextType
  56. {
  57. get { return _ContextType; }
  58. }
  59. // just because of this, the whole model can not be cached efficiently, since we can not guarantee
  60. // that another mapping source instance will not use the same model
  61. private MappingSource _MappingSource;
  62. /// <summary>
  63. /// The mapping source used for that model.
  64. /// </summary>
  65. public override MappingSource MappingSource
  66. {
  67. get { return _MappingSource; }
  68. }
  69. private string _DatabaseName;
  70. /// <summary>
  71. /// Name of the database.
  72. /// </summary>
  73. /// <remarks>
  74. /// The name of the database is the type name of the DataContext inheriting class.
  75. /// If a plain DataContext is used, the database name is "DataContext".
  76. /// </remarks>
  77. public override string DatabaseName
  78. {
  79. get {
  80. if (_DatabaseName == null)
  81. DiscoverDatabaseName();
  82. return _DatabaseName;
  83. }
  84. }
  85. //Currently not implemented Properties
  86. public override Type ProviderType
  87. {
  88. get { throw new NotImplementedException(); }
  89. }
  90. //This function will try to add unknown table types
  91. private IDictionary<Type, MetaTable> _Tables = new Dictionary<Type, MetaTable>();
  92. /// <summary>
  93. /// Initializes a new instance of the <see cref="AttributedMetaModel"/> class.
  94. /// </summary>
  95. /// <param name="contextType">DataContext type used.</param>
  96. /// <param name="mappingSource">The mapping source.</param>
  97. public AttributedMetaModel(Type contextType, MappingSource mappingSource)
  98. {
  99. _ContextType = contextType;
  100. _MappingSource = mappingSource;
  101. }
  102. /// <summary>
  103. /// Gets the <see cref="MetaFunction"/> for the given MethodInfo.
  104. /// </summary>
  105. /// <param name="method">The method info for which the <see cref="MetaFunction"/> should be returned.</param>
  106. public override MetaFunction GetFunction(MethodInfo method)
  107. {
  108. return GetFunctions().SingleOrDefault(m => m.Method == method);
  109. }
  110. /// <summary>
  111. /// Returns an enumeration of all mapped functions.
  112. /// </summary>
  113. public override IEnumerable<MetaFunction> GetFunctions()
  114. {
  115. const BindingFlags scope = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
  116. foreach (var methodInfo in _ContextType.GetMethods(scope))
  117. {
  118. var function = methodInfo.GetAttribute<FunctionAttribute>();
  119. if (function != null)
  120. yield return new AttributedMetaFunction(methodInfo, function);
  121. }
  122. }
  123. public override MetaType GetMetaType(Type type)
  124. {
  125. var metaTable = GetTable(type);
  126. if (metaTable == null)
  127. return null;
  128. return metaTable.RowType;
  129. }
  130. /// <summary>
  131. /// Returns the <see cref="MetaTable"/> for the given table type.
  132. /// </summary>
  133. /// <remarks>
  134. /// If the given type is not allready mapped it tries to map it.
  135. /// </remarks>
  136. /// <param name="tableType"><see cref="MetaTable"/> for the table type or null if not mappable.</param>
  137. public override MetaTable GetTable(Type tableType)
  138. {
  139. MetaTable metaTable;
  140. _Tables.TryGetValue(tableType, out metaTable);
  141. if (metaTable != null)
  142. {
  143. return metaTable;
  144. }
  145. return GetTables().FirstOrDefault(t => t.RowType.Type == tableType)
  146. ?? AddTableType(tableType);
  147. }
  148. /// <summary>
  149. /// Returns an enumeration of all mapped tables.
  150. /// </summary>
  151. //Discover all the tables used with this context, used for the GetTable/GetTables function
  152. //Behaviour of GetTables in the Framework: STRANGE
  153. //If the DataContext was a strong typed one (derived with fields for the tables),
  154. //it returns a list of MetaTables for all this tables.
  155. //But if you call GetTable<T> with an additional table - the table doesn't get added to this list.
  156. //If you use a vanilla DataContext the list is empty at the beginning (ok no surprise here),
  157. //if you call GetTable<T> here the table is added to the list.
  158. //
  159. //If you add to properties with the same T of Table<T> only the first gets into the list.
  160. public override IEnumerable<MetaTable> GetTables()
  161. {
  162. const BindingFlags scope = BindingFlags.GetField |
  163. BindingFlags.GetProperty | BindingFlags.Static |
  164. BindingFlags.Instance | BindingFlags.NonPublic |
  165. BindingFlags.Public;
  166. var seen = new HashSet<Type>();
  167. foreach (var info in _ContextType.GetMembers(scope))
  168. {
  169. // Only look for Fields & Properties.
  170. if (info.MemberType != MemberTypes.Field && info.MemberType != MemberTypes.Property)
  171. continue;
  172. Type memberType = info.GetMemberType();
  173. if (memberType == null || !memberType.IsGenericType ||
  174. memberType.GetGenericTypeDefinition() != typeof(Table<>))
  175. continue;
  176. var tableType = memberType.GetGenericArguments()[0];
  177. if (tableType.IsGenericParameter)
  178. continue;
  179. if (seen.Contains(tableType))
  180. continue;
  181. seen.Add(tableType);
  182. MetaTable metaTable;
  183. if (_Tables.TryGetValue(tableType, out metaTable))
  184. yield return metaTable;
  185. else
  186. yield return AddTableType(tableType);
  187. }
  188. }
  189. /// <summary>
  190. /// Tries to discover the name of the database.
  191. /// Database name == class name of the DataContext's most derived class used for this MetaModel.
  192. /// </summary>
  193. private void DiscoverDatabaseName()
  194. {
  195. var databaseAttribute = _ContextType.GetAttribute<DatabaseAttribute>();
  196. if (databaseAttribute != null)
  197. {
  198. _DatabaseName = databaseAttribute.Name;
  199. }
  200. else //Found no DatabaseAttribute get the class name
  201. {
  202. _DatabaseName = _ContextType.Name;
  203. }
  204. }
  205. /// <summary>
  206. /// Adds the table of the given type to the mappings.
  207. /// </summary>
  208. /// <remarks>
  209. /// The given type must have a <see cref="TableAttribute" /> to be mappable.
  210. /// </remarks>
  211. /// <param name="tableType">Type of the table.</param>
  212. /// <returns>
  213. /// Returns the <see cref="MetaTable"/> for the given table type or null if it is not mappable.
  214. /// </returns>
  215. private MetaTable AddTableType(Type tableType)
  216. {
  217. //No need to check base types because framework implementation doesn't do this either
  218. var tableAttribute = tableType.GetAttribute<TableAttribute>();
  219. if (tableAttribute == null)
  220. {
  221. return null;
  222. }
  223. //First set up the table without associations
  224. var metaType = new AttributedMetaType(tableType);
  225. var metaTable = new AttributedMetaTable(tableAttribute, metaType, this);
  226. metaType.SetMetaTable(metaTable);
  227. _Tables[tableType] = metaTable;
  228. return metaTable;
  229. }
  230. }
  231. }