2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.Data.Linq / src / DbLinq / Data / Linq / Table.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne\r
6 // \r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy\r
8 // of this software and associated documentation files (the "Software"), to deal\r
9 // in the Software without restriction, including without limitation the rights\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
11 // copies of the Software, and to permit persons to whom the Software is\r
12 // furnished to do so, subject to the following conditions:\r
13 // \r
14 // The above copyright notice and this permission notice shall be included in\r
15 // all copies or substantial portions of the Software.\r
16 // \r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
23 // THE SOFTWARE.\r
24 // \r
25 #endregion\r
26 \r
27 using System;\r
28 using System.Data;\r
29 using System.Data.Linq;\r
30 using System.Reflection;\r
31 using System.Diagnostics;\r
32 using System.Collections;\r
33 using System.Collections.Generic;\r
34 using System.Linq;\r
35 using System.Linq.Expressions;\r
36 using System.ComponentModel;\r
37 \r
38 #if MONO_STRICT\r
39 using System.Data.Linq.Implementation;\r
40 using System.Data.Linq.Sugar;\r
41 using ITable = System.Data.Linq.ITable;\r
42 #else\r
43 using DbLinq.Data.Linq.Implementation;\r
44 using DbLinq.Data.Linq.Sugar;\r
45 using ITable = DbLinq.Data.Linq.ITable;\r
46 #endif\r
47 \r
48 using DbLinq;\r
49 \r
50 \r
51 #if MONO_STRICT\r
52 namespace System.Data.Linq\r
53 #else\r
54 namespace DbLinq.Data.Linq\r
55 #endif\r
56 {\r
57     /// <summary>\r
58     /// T may be eg. class Employee or string - the output\r
59     /// </summary>\r
60     /// <typeparam name="TEntity">The type of the entity.</typeparam>\r
61     public sealed partial class Table<TEntity> :\r
62             ITable,\r
63             IQueryProvider,\r
64             IListSource,\r
65             IEnumerable<TEntity>,\r
66             IEnumerable,\r
67             IQueryable<TEntity>,\r
68             IQueryable\r
69             where TEntity : class\r
70     {\r
71         /// <summary>\r
72         /// the parent DataContext holds our connection etc\r
73         /// </summary>\r
74         public DataContext Context { get; private set; }\r
75 \r
76         // QueryProvider is the running entity, running through nested Expressions\r
77         private readonly QueryProvider<TEntity> _queryProvider;\r
78 \r
79         /// <summary>\r
80         /// Initializes a new instance of the <see cref="Table&lt;TEntity&gt;"/> class.\r
81         /// </summary>\r
82         /// <param name="parentContext">The parent context.</param>\r
83         internal Table(DataContext parentContext)\r
84         {\r
85             Context = parentContext;\r
86             _queryProvider = new QueryProvider<TEntity>(parentContext);\r
87         }\r
88 \r
89         /// <summary>\r
90         /// 'S' is the projected type. If you say 'from e in Employees select e.ID', then type S will be int.\r
91         /// If you say 'select new {e.ID}', then type S will be something like Projection.f__1\r
92         /// </summary>\r
93         IQueryable<S> IQueryProvider.CreateQuery<S>(Expression expr)\r
94         {\r
95             return _queryProvider.CreateQuery<S>(expr);\r
96         }\r
97 \r
98         /// <summary>\r
99         /// this is only called during Dynamic Linq\r
100         /// </summary>\r
101         IQueryable IQueryProvider.CreateQuery(Expression expression)\r
102         {\r
103             return _queryProvider.CreateQuery(expression);\r
104         }\r
105 \r
106         /// <summary>\r
107         /// the query '(from o in Orders select o).First()' enters here\r
108         /// </summary>\r
109         S IQueryProvider.Execute<S>(Expression expression)\r
110         {\r
111             return _queryProvider.Execute<S>(expression);\r
112         }\r
113 \r
114         /// <summary>\r
115         /// Executes the current expression\r
116         /// </summary>\r
117         /// <param name="expression"></param>\r
118         /// <returns></returns>\r
119         object IQueryProvider.Execute(Expression expression)\r
120         {\r
121             return _queryProvider.Execute(expression);\r
122         }\r
123 \r
124         /// <summary>\r
125         /// entry point for 'foreach' statement.\r
126         /// </summary>\r
127         public IEnumerator<TEntity> GetEnumerator()\r
128         {\r
129             var queryable = this as IQueryable<TEntity>;\r
130             var query = queryable.Select(t => t);\r
131             return query.GetEnumerator();\r
132         }\r
133 \r
134         IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()\r
135         {\r
136             return GetEnumerator();\r
137         }\r
138 \r
139         /// <summary>\r
140         /// Enumerates all table items\r
141         /// </summary>\r
142         /// <returns></returns>\r
143         IEnumerator IEnumerable.GetEnumerator()\r
144         {\r
145             return GetEnumerator();\r
146         }\r
147 \r
148         Type IQueryable.ElementType\r
149         {\r
150             get { return _queryProvider.ElementType; }\r
151         }\r
152 \r
153         /// <summary>\r
154         /// Returns this table as an Expression\r
155         /// </summary>\r
156         Expression IQueryable.Expression\r
157         {\r
158             get { return Expression.Constant(this); } // do not change this to _queryProvider.Expression, Sugar doesn't fully handle QueryProviders by now\r
159         }\r
160 \r
161         /// <summary>\r
162         /// IQueryable.Provider: represents the Table as a IQueryable provider (hence the name)\r
163         /// </summary>\r
164         IQueryProvider IQueryable.Provider\r
165         {\r
166             get { return _queryProvider.Provider; }\r
167         }\r
168 \r
169         #region Insert functions\r
170 \r
171         void ITable.InsertOnSubmit(object entity)\r
172         {\r
173             Context.RegisterInsert(entity);\r
174         }\r
175 \r
176         public void InsertOnSubmit(TEntity entity)\r
177         {\r
178             Context.RegisterInsert(entity);\r
179         }\r
180 \r
181         void ITable.InsertAllOnSubmit(IEnumerable entities)\r
182         {\r
183             foreach (var entity in entities)\r
184                 Context.RegisterInsert(entity);\r
185         }\r
186 \r
187         public void InsertAllOnSubmit<TSubEntity>(IEnumerable<TSubEntity> entities) where TSubEntity : TEntity\r
188         {\r
189             if (entities == null)\r
190                 throw new ArgumentNullException("entities");\r
191 \r
192             foreach (var entity in entities)\r
193                 Context.RegisterInsert(entity);\r
194         }\r
195 \r
196         #endregion\r
197 \r
198         #region Delete functions\r
199 \r
200         void ITable.DeleteAllOnSubmit(IEnumerable entities)\r
201         {\r
202             foreach (var entity in entities)\r
203                 Context.RegisterDelete(entity);\r
204         }\r
205 \r
206         /// <summary>\r
207         /// required by ITable interface\r
208         /// </summary>\r
209         /// <param name="entity"></param>\r
210         void ITable.DeleteOnSubmit(object entity)\r
211         {\r
212             Context.RegisterDelete(entity);\r
213         }\r
214 \r
215         public void DeleteOnSubmit(TEntity entity)\r
216         {\r
217             Context.RegisterDelete(entity);\r
218         }\r
219 \r
220         public void DeleteAllOnSubmit<TSubEntity>(IEnumerable<TSubEntity> entities) where TSubEntity : TEntity\r
221         {\r
222             if (entities == null)\r
223                 throw new ArgumentNullException("entities");\r
224 \r
225             foreach (var row in entities)\r
226                 Context.RegisterDelete(row);\r
227         }\r
228 \r
229         #endregion\r
230 \r
231         #region Attach functions\r
232 \r
233         /// <summary>\r
234         /// required for ITable\r
235         /// </summary>\r
236         /// <param name="entity"></param>\r
237         void ITable.Attach(object entity)\r
238         {\r
239             Context.RegisterUpdate(entity);\r
240         }\r
241 \r
242         void ITable.Attach(object entity, object original)\r
243         {\r
244             Context.RegisterUpdate(entity, original);\r
245         }\r
246 \r
247         void ITable.Attach(object entity, bool asModified)\r
248         {\r
249             Context.RegisterUpdate(entity, asModified ? null : entity);\r
250         }\r
251 \r
252         void ITable.AttachAll(IEnumerable entities)\r
253         {\r
254             foreach (var entity in entities)\r
255                 Context.RegisterUpdate(entity);\r
256         }\r
257         void ITable.AttachAll(IEnumerable entities, bool asModified)\r
258         {\r
259             foreach (var entity in entities)\r
260                 Context.RegisterUpdate(entity);\r
261         }\r
262 \r
263         /// <summary>\r
264         /// Attaches an entity from another Context to a table,\r
265         /// with the intention to perform an update or delete operation\r
266         /// </summary>\r
267         /// <param name="entity">table row object to attach</param>\r
268         public void Attach(TEntity entity)\r
269         {\r
270             Context.RegisterUpdate(entity);\r
271         }\r
272 \r
273         [DbLinqToDo]\r
274         public void Attach(TEntity entity, bool asModified)\r
275         {\r
276             throw new NotImplementedException();\r
277         }\r
278 \r
279         public void AttachAll<TSubEntity>(IEnumerable<TSubEntity> entities) where TSubEntity : TEntity\r
280         {\r
281             if (entities == null)\r
282                 throw new ArgumentNullException("entities");\r
283 \r
284             foreach (var entity in entities)\r
285                 Context.RegisterUpdate(entity);\r
286         }\r
287 \r
288         [DbLinqToDo]\r
289         public void AttachAll<TSubEntity>(IEnumerable<TSubEntity> entities, bool asModified) where TSubEntity : TEntity\r
290         {\r
291             throw new NotImplementedException();\r
292         }\r
293 \r
294         /// <summary>\r
295         /// Attaches existing entity with original state\r
296         /// </summary>\r
297         /// <param name="entity">live entity added to change tracking</param>\r
298         /// <param name="original">original unchanged property values</param>\r
299         public void Attach(TEntity entity, TEntity original)\r
300         {\r
301             Context.RegisterUpdate(entity, original);\r
302         }\r
303 \r
304         #endregion\r
305 \r
306         /// <summary>\r
307         /// Gets a value indicating whether this instance is read only.\r
308         /// </summary>\r
309         /// <value>\r
310         ///     <c>true</c> if this instance is read only; otherwise, <c>false</c>.\r
311         /// </value>\r
312         public bool IsReadOnly { get { return false; } }\r
313 \r
314         // PC: this will probably required to recreate a new object instance with all original values\r
315         //     (that we currently do not always store, so we may need to make a differential copy\r
316         [Obsolete("NOT IMPLEMENTED YET")]\r
317         [DbLinqToDo]\r
318         ModifiedMemberInfo[] ITable.GetModifiedMembers(object entity)\r
319         {\r
320             throw new ApplicationException("L579 Not implemented");\r
321         }\r
322 \r
323         // PC: complementary to GetModifiedMembers(), we probably need a few changes to the IMemberModificationHandler,\r
324         //     to recall original values\r
325         [Obsolete("NOT IMPLEMENTED YET")]\r
326         [DbLinqToDo]\r
327         object ITable.GetOriginalEntityState(object entity)\r
328         {\r
329             throw new ApplicationException("L585 Not implemented");\r
330         }\r
331 \r
332         bool IListSource.ContainsListCollection\r
333         {\r
334             get { return true; }\r
335         }\r
336 \r
337         IList IListSource.GetList()\r
338         {\r
339             return this.ToList();\r
340         }\r
341 \r
342         [DbLinqToDo]\r
343         public TEntity GetOriginalEntityState(TEntity entity)\r
344         {\r
345             if (entity == null)\r
346                 throw new ArgumentNullException("entity");\r
347 \r
348             throw new NotImplementedException();\r
349         }\r
350 \r
351         [DbLinqToDo]\r
352         public IBindingList GetNewBindingList()\r
353         {\r
354             throw new NotImplementedException();\r
355         }\r
356 \r
357         [DbLinqToDo]\r
358         public ModifiedMemberInfo[] GetModifiedMembers(TEntity entity)\r
359         {\r
360             if (entity == null)\r
361                 throw new ArgumentNullException("entity");\r
362 \r
363             throw new NotImplementedException();\r
364         }\r
365 \r
366         public override string ToString()\r
367         {\r
368             return string.Format("Table({0})", typeof(TEntity).Name);\r
369         }\r
370     }\r
371 }\r