PageRenderTime 48ms CodeModel.GetById 32ms app.highlight 13ms 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
 20using System;
 21using System.Data.Linq;
 22using System.Data.Linq.Mapping;
 23using System.Linq;
 24using System.Linq.Expressions;
 25using System.Xml.Linq;
 26using NAom.Core;
 27
 28namespace NAom.DAL
 29{
 30  public class EntityRepository<TEntity> : IRepository<TEntity>
 31    where TEntity : class, IEntity  //, new()
 32  {
 33
 34    private readonly DynamicType<TEntity> _dynamicType;
 35    private readonly IDynamicTypeFactory<TEntity> _dynamicTypeFactory;
 36
 37    private readonly DataContext _dbCtx;
 38    private readonly ITable _linq2SQLTable;
 39
 40    public EntityRepository(EntityType entityType)
 41    {
 42      EntityType = entityType;
 43
 44      _dynamicType = CreateDynamicType(entityType);
 45      _dynamicTypeFactory = _dynamicType.CreateFactory();
 46
 47      #region Goo
 48
 49      // since Type.GetType(string) != _dynamicTypeFactory.GeneratedType for dynamic assemblies,
 50      //  DataContext.GetTable() fails with InvalidOperationException: Could not retrieve a Table for inheritance subtype 'TDynamicType', try Table of TDynamicType instead. 
 51      // hook up TypeResolve, so that the correct type can be returned to
 52      //  the DataContext when it's busy reflecting
 53      Type generatedType = _dynamicTypeFactory.GeneratedType;
 54
 55      ResolveEventHandler resolveEventHandler = (o, e) =>
 56      {
 57        if (String.CompareOrdinal(generatedType.FullName, e.Name) == 0)
 58          return generatedType.Assembly;
 59        return null;
 60      };
 61
 62      AppDomain.CurrentDomain.TypeResolve += resolveEventHandler;
 63
 64      #endregion
 65
 66      _dbCtx = CreateDataContext(entityType, _dynamicTypeFactory.GeneratedType);
 67      _linq2SQLTable = GetTable(_dynamicTypeFactory.GeneratedType);
 68
 69      #region Goo
 70
 71      // clean up, remove handler
 72      AppDomain.CurrentDomain.TypeResolve -= resolveEventHandler;
 73
 74      #endregion
 75
 76#if DEBUG
 77      _dbCtx.Log = Console.Out;
 78#endif
 79
 80    }
 81
 82    public EntityType EntityType { get; private set; }
 83
 84    #region IRepository<TEntity> Members
 85
 86    public TEntity CreateInstance()
 87    {
 88      return _dynamicTypeFactory.CreateInstance();
 89    }
 90
 91    public IQueryable<TEntity> GetAll()
 92    {
 93      return new InternalEntityQueryable<TEntity>
 94        (
 95          _dynamicTypeFactory.GeneratedType,
 96          _linq2SQLTable.AsQueryable().OfType<TEntity>()
 97        );
 98    }
 99
100    public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
101    {
102      return GetAll().Where(expression);
103    }
104
105    public void Add(TEntity entity)
106    {
107      _linq2SQLTable.InsertOnSubmit(entity);
108      _dbCtx.SubmitChanges();
109    }
110
111    public void Update(TEntity entity)
112    {
113      _linq2SQLTable.DeleteOnSubmit(entity);
114      _dbCtx.SubmitChanges();
115    }
116
117    public void Delete(TEntity entity)
118    {
119      _linq2SQLTable.DeleteOnSubmit(entity);
120      _dbCtx.SubmitChanges();
121    }
122
123    public void Delete(Expression<Func<TEntity, bool>> expression)
124    {
125      foreach (TEntity entity in GetAll().Where(expression))
126      {
127        _linq2SQLTable.DeleteOnSubmit(entity);
128      }
129      _dbCtx.SubmitChanges();
130    }
131
132    #endregion
133
134    #region Support
135
136    private static DynamicType<TEntity> CreateDynamicType(EntityType entityType)
137    {
138      Type genericPropertyTypeType = typeof(PropertyType<>);
139
140      DynamicType<TEntity> dynamicType = new DynamicType<TEntity>(entityType.Name);
141
142      // add required property types
143      dynamicType.Properties.AddRange(InterfaceSupport.DerivePropertyTypes(typeof(IEntity)));
144
145      // now add user-defined properties
146      foreach (IInternalAttributeType attributeType in entityType.AttributeTypes)
147      {
148        Type propertyTypeType = genericPropertyTypeType.MakeGenericType(attributeType.RealDataType);
149        IPropertyType propertyType = (IPropertyType)Activator.CreateInstance(propertyTypeType, new object[] { attributeType.Name });
150        dynamicType.Properties.Add(propertyType);
151
152        // store for later
153        attributeType.PropertyType = propertyType;
154      }
155
156      return dynamicType;
157
158    }
159
160    private static DataContext CreateDataContext(EntityType entityType, Type generatedType)
161    {
162
163      // generate Linq2SQL mapping
164      XDocument mappingXmlDoc = CreateXmlMappingSource(entityType, generatedType);
165
166      // load it
167      XmlMappingSource mappingSource = XmlMappingSource.FromXml(mappingXmlDoc.ToString());
168
169      // create the data context using this mapping
170      DataContext dbCtx = new DataContext(Properties.Settings.Default.AomDBConnectionString, mappingSource);
171
172      return dbCtx;
173    }
174
175    private ITable GetTable(Type generatedType)
176    {
177      // get the table for the generated type
178      return _dbCtx.GetTable(generatedType);
179    }
180
181    private static XDocument CreateXmlMappingSource(EntityType entityType, Type generatedType)
182    {
183      // NOTE: 
184      //  The Name column is set as the primary key, since scope_identity() doesn't work
185      //  for views which have "instead of" triggers
186
187      XElement typeXElement;
188      XNamespace xmlns = "http://schemas.microsoft.com/linqtosql/mapping/2007";
189      XDocument mappingXmlDoc = new XDocument
190        (
191        new XElement
192          (
193            xmlns + "Database",
194            new XAttribute("xmlns", xmlns.NamespaceName),
195            new XAttribute("Name", "AomDB"),
196            new XElement
197            (
198              xmlns + "Table",
199              new XAttribute("Name", entityType.GeneratedViewName),
200              typeXElement = new XElement
201               (
202                 xmlns + "Type",
203                 new XAttribute("Name", generatedType.FullName),
204                 new XElement
205                 (
206                    xmlns + "Column",
207                    new XAttribute("Name", "Id"),
208                    new XAttribute("Member", "Id"),
209                    new XAttribute("Storage", "_dynamicId"),
210                    new XAttribute("AutoSync", "OnInsert"),
211                    new XAttribute("IsDbGenerated", true),
212                    new XAttribute("CanBeNull", false),
213                    new XAttribute("UpdateCheck", "Never")
214                 ),
215                 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")),
216                 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"))
217               )
218            )
219          )
220        );
221
222      foreach (IInternalAttributeType attributeType in entityType.AttributeTypes)
223      {
224        typeXElement.Add
225          (
226            new XElement
227              (
228                xmlns + "Column",
229                new XAttribute("Name", attributeType.Name),
230                new XAttribute("Member", attributeType.Name),
231                new XAttribute("Storage", "_dynamic" + attributeType.Name),
232                new XAttribute("CanBeNull", !attributeType.RealDataType.IsValueType),
233                new XAttribute("UpdateCheck", "Never")
234              )
235          );
236      }
237
238      return mappingXmlDoc;
239    }
240
241    #endregion
242
243  }
244}