PageRenderTime 96ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/Prototypes/AomDB/NAomDAL/DAL/EntityRepository.cs

https://bitbucket.org/virtualstaticvoid/naom
C# | 244 lines | 166 code | 47 blank | 31 comment | 2 complexity | d5731cd7528fb3cbe75d713b00c06cae MD5 | raw file
  1. #region Copyright
  2. //
  3. // Copyright (C) 2008 VirtualStaticVoid <virtualstaticvoid@gmail.com>
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. //
  18. #endregion
  19. using System;
  20. using System.Data.Linq;
  21. using System.Data.Linq.Mapping;
  22. using System.Linq;
  23. using System.Linq.Expressions;
  24. using System.Xml.Linq;
  25. using NAom.Core;
  26. namespace NAom.DAL
  27. {
  28. public class EntityRepository<TEntity> : IRepository<TEntity>
  29. where TEntity : class, IEntity //, new()
  30. {
  31. private readonly DynamicType<TEntity> _dynamicType;
  32. private readonly IDynamicTypeFactory<TEntity> _dynamicTypeFactory;
  33. private readonly DataContext _dbCtx;
  34. private readonly ITable _linq2SQLTable;
  35. public EntityRepository(EntityType entityType)
  36. {
  37. EntityType = entityType;
  38. _dynamicType = CreateDynamicType(entityType);
  39. _dynamicTypeFactory = _dynamicType.CreateFactory();
  40. #region Goo
  41. // since Type.GetType(string) != _dynamicTypeFactory.GeneratedType for dynamic assemblies,
  42. // DataContext.GetTable() fails with InvalidOperationException: Could not retrieve a Table for inheritance subtype 'TDynamicType', try Table of TDynamicType instead.
  43. // hook up TypeResolve, so that the correct type can be returned to
  44. // the DataContext when it's busy reflecting
  45. Type generatedType = _dynamicTypeFactory.GeneratedType;
  46. ResolveEventHandler resolveEventHandler = (o, e) =>
  47. {
  48. if (String.CompareOrdinal(generatedType.FullName, e.Name) == 0)
  49. return generatedType.Assembly;
  50. return null;
  51. };
  52. AppDomain.CurrentDomain.TypeResolve += resolveEventHandler;
  53. #endregion
  54. _dbCtx = CreateDataContext(entityType, _dynamicTypeFactory.GeneratedType);
  55. _linq2SQLTable = GetTable(_dynamicTypeFactory.GeneratedType);
  56. #region Goo
  57. // clean up, remove handler
  58. AppDomain.CurrentDomain.TypeResolve -= resolveEventHandler;
  59. #endregion
  60. #if DEBUG
  61. _dbCtx.Log = Console.Out;
  62. #endif
  63. }
  64. public EntityType EntityType { get; private set; }
  65. #region IRepository<TEntity> Members
  66. public TEntity CreateInstance()
  67. {
  68. return _dynamicTypeFactory.CreateInstance();
  69. }
  70. public IQueryable<TEntity> GetAll()
  71. {
  72. return new InternalEntityQueryable<TEntity>
  73. (
  74. _dynamicTypeFactory.GeneratedType,
  75. _linq2SQLTable.AsQueryable().OfType<TEntity>()
  76. );
  77. }
  78. public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
  79. {
  80. return GetAll().Where(expression);
  81. }
  82. public void Add(TEntity entity)
  83. {
  84. _linq2SQLTable.InsertOnSubmit(entity);
  85. _dbCtx.SubmitChanges();
  86. }
  87. public void Update(TEntity entity)
  88. {
  89. _linq2SQLTable.DeleteOnSubmit(entity);
  90. _dbCtx.SubmitChanges();
  91. }
  92. public void Delete(TEntity entity)
  93. {
  94. _linq2SQLTable.DeleteOnSubmit(entity);
  95. _dbCtx.SubmitChanges();
  96. }
  97. public void Delete(Expression<Func<TEntity, bool>> expression)
  98. {
  99. foreach (TEntity entity in GetAll().Where(expression))
  100. {
  101. _linq2SQLTable.DeleteOnSubmit(entity);
  102. }
  103. _dbCtx.SubmitChanges();
  104. }
  105. #endregion
  106. #region Support
  107. private static DynamicType<TEntity> CreateDynamicType(EntityType entityType)
  108. {
  109. Type genericPropertyTypeType = typeof(PropertyType<>);
  110. DynamicType<TEntity> dynamicType = new DynamicType<TEntity>(entityType.Name);
  111. // add required property types
  112. dynamicType.Properties.AddRange(InterfaceSupport.DerivePropertyTypes(typeof(IEntity)));
  113. // now add user-defined properties
  114. foreach (IInternalAttributeType attributeType in entityType.AttributeTypes)
  115. {
  116. Type propertyTypeType = genericPropertyTypeType.MakeGenericType(attributeType.RealDataType);
  117. IPropertyType propertyType = (IPropertyType)Activator.CreateInstance(propertyTypeType, new object[] { attributeType.Name });
  118. dynamicType.Properties.Add(propertyType);
  119. // store for later
  120. attributeType.PropertyType = propertyType;
  121. }
  122. return dynamicType;
  123. }
  124. private static DataContext CreateDataContext(EntityType entityType, Type generatedType)
  125. {
  126. // generate Linq2SQL mapping
  127. XDocument mappingXmlDoc = CreateXmlMappingSource(entityType, generatedType);
  128. // load it
  129. XmlMappingSource mappingSource = XmlMappingSource.FromXml(mappingXmlDoc.ToString());
  130. // create the data context using this mapping
  131. DataContext dbCtx = new DataContext(Properties.Settings.Default.AomDBConnectionString, mappingSource);
  132. return dbCtx;
  133. }
  134. private ITable GetTable(Type generatedType)
  135. {
  136. // get the table for the generated type
  137. return _dbCtx.GetTable(generatedType);
  138. }
  139. private static XDocument CreateXmlMappingSource(EntityType entityType, Type generatedType)
  140. {
  141. // NOTE:
  142. // The Name column is set as the primary key, since scope_identity() doesn't work
  143. // for views which have "instead of" triggers
  144. XElement typeXElement;
  145. XNamespace xmlns = "http://schemas.microsoft.com/linqtosql/mapping/2007";
  146. XDocument mappingXmlDoc = new XDocument
  147. (
  148. new XElement
  149. (
  150. xmlns + "Database",
  151. new XAttribute("xmlns", xmlns.NamespaceName),
  152. new XAttribute("Name", "AomDB"),
  153. new XElement
  154. (
  155. xmlns + "Table",
  156. new XAttribute("Name", entityType.GeneratedViewName),
  157. typeXElement = new XElement
  158. (
  159. xmlns + "Type",
  160. new XAttribute("Name", generatedType.FullName),
  161. new XElement
  162. (
  163. xmlns + "Column",
  164. new XAttribute("Name", "Id"),
  165. new XAttribute("Member", "Id"),
  166. new XAttribute("Storage", "_dynamicId"),
  167. new XAttribute("AutoSync", "OnInsert"),
  168. new XAttribute("IsDbGenerated", true),
  169. new XAttribute("CanBeNull", false),
  170. new XAttribute("UpdateCheck", "Never")
  171. ),
  172. new XElement(xmlns + "Column", new XAttribute("Name", "Version"), new XAttribute("Member", "Version"), new XAttribute("Storage", "_dynamicVersion"), new XAttribute("AutoSync", "Always"), new XAttribute("IsDbGenerated", true), new XAttribute("IsVersion", true), new XAttribute("CanBeNull", false), new XAttribute("UpdateCheck", "Never")),
  173. new XElement(xmlns + "Column", new XAttribute("Name", "Name"), new XAttribute("Member", "Name"), new XAttribute("Storage", "_dynamicName"), new XAttribute("IsPrimaryKey", true), new XAttribute("CanBeNull", false), new XAttribute("UpdateCheck", "Never"))
  174. )
  175. )
  176. )
  177. );
  178. foreach (IInternalAttributeType attributeType in entityType.AttributeTypes)
  179. {
  180. typeXElement.Add
  181. (
  182. new XElement
  183. (
  184. xmlns + "Column",
  185. new XAttribute("Name", attributeType.Name),
  186. new XAttribute("Member", attributeType.Name),
  187. new XAttribute("Storage", "_dynamic" + attributeType.Name),
  188. new XAttribute("CanBeNull", !attributeType.RealDataType.IsValueType),
  189. new XAttribute("UpdateCheck", "Never")
  190. )
  191. );
  192. }
  193. return mappingXmlDoc;
  194. }
  195. #endregion
  196. }
  197. }