/Prototypes/AomDB/NAomDAL/DAL/EntityRepository.cs
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}