2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System.Data.Linq / src / DbLinq / Data / Linq / Mapping / XmlMappingSource.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Stefan Klinger\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 #region grammar\r
28 /* ----------------\r
29 default namespace = "http://schemas.microsoft.com/linqtosql/mapping/2007"\r
30 grammar {\r
31 \r
32 start = element Database { Database }\r
33 \r
34 Database = {\r
35   element Table { Table }*,\r
36   element Function { Function }*,\r
37   attribute Name { text }?,\r
38   attribute Provider { text }?\r
39 }\r
40 \r
41 Table = {\r
42   element Type { Type },\r
43   attribute Name { text }?,\r
44   attribute Member { text }?\r
45 }\r
46 \r
47 Type = {\r
48   {\r
49     element Column { Column }* |\r
50     element Association { Association }*\r
51   }*,\r
52   element Type { Type }*,\r
53   attribute Name { text },\r
54   attribute InheritanceCode { text }?,\r
55   attribute IsInheritanceDefault { boolean }?\r
56 }\r
57 \r
58 Column = {\r
59   attribute Name { text }?,\r
60   attribute Member { text },\r
61   attribute Storage { text }?,\r
62   attribute DbType { text }?,\r
63   attribute IsPrimaryKey { boolean }?,\r
64   attribute IsDbGenerated { boolean }?,\r
65   attribute CanBeNull { boolean }?,\r
66   attribute UpdateCheck { UpdateCheck }?,\r
67   attribute IsDiscriminator { boolean }?,\r
68   attribute Expression { text }?,\r
69   attribute IsVersion { boolean }?,\r
70   attribute AutoSync { AutoSync}?\r
71 }\r
72 \r
73 Association = {\r
74   attribute Name { text }?,\r
75   attribute Member { text },\r
76   attribute Storage { text }?,\r
77   attribute ThisKey { text }?,\r
78   attribute OtherKey { text }?,\r
79   attribute IsForeignKey { boolean }?,\r
80   attribute IsUnique { boolean }?,\r
81   attribute DeleteRule { text }?,\r
82   attribute DeleteOnNull { boolean }?\r
83 }\r
84 \r
85 Function = {\r
86   element Parameter { Parameter }*,\r
87   {\r
88     element ElementType { Type }* |\r
89     element Return { Return }\r
90   },\r
91   attribute Name { text }?,\r
92   attribute Method { text },\r
93   attribute IsComposable { boolean }?\r
94 }\r
95 \r
96 Parameter = {\r
97   attribute Name { text }?,\r
98   attribute Parameter { text },\r
99   attribute DbType { text }?,\r
100   attribute Direction { ParameterDirection }?\r
101 }\r
102 \r
103 Return = attribute DbType { text}?\r
104 \r
105 UpdateCheck = "Always" | "Never" | "WhenChanged"\r
106 ParameterDirection = "In" | "Out" | "InOut"\r
107 AutoSync = "Never" | "OnInsert" | "OnUpdate" | "Always" | "Default"\r
108 \r
109 }\r
110 ---------------- */\r
111 #endregion\r
112 \r
113 using System;\r
114 using System.Collections.Generic;\r
115 using System.Collections.ObjectModel;\r
116 using System.IO;\r
117 using System.Linq;\r
118 using System.Reflection;\r
119 using System.Xml;\r
120 using DbLinq;\r
121 using DbLinq.Schema.Dbml;\r
122 using DbLinq.Util;\r
123 \r
124 #if MONO_STRICT\r
125 namespace System.Data.Linq.Mapping\r
126 #else\r
127 namespace DbLinq.Data.Linq.Mapping\r
128 #endif\r
129 {\r
130     public sealed class XmlMappingSource : System.Data.Linq.Mapping.MappingSource\r
131     {\r
132         DbmlDatabase db;\r
133 \r
134         XmlMappingSource(XmlReader reader)\r
135         {\r
136             db = new DbmlDatabase(reader);\r
137         }\r
138 \r
139         public static XmlMappingSource FromReader(XmlReader reader)\r
140         {\r
141             return new XmlMappingSource(reader);\r
142         }\r
143 \r
144         public static XmlMappingSource FromStream(Stream stream)\r
145         {\r
146             return FromReader(XmlReader.Create(stream));\r
147         }\r
148 \r
149         public static XmlMappingSource FromUrl(string url)\r
150         {\r
151             return FromReader(XmlReader.Create(url));\r
152         }\r
153 \r
154         public static XmlMappingSource FromXml(string xml)\r
155         {\r
156             return FromReader(XmlReader.Create(new StringReader(xml)));\r
157         }\r
158 \r
159         protected override System.Data.Linq.Mapping.MetaModel CreateModel(System.Type dataContextType)\r
160         {\r
161             return new XmlMetaModel(this, db, dataContextType);\r
162         }\r
163 \r
164 \r
165         abstract class DbmlItem\r
166         {\r
167             public const string DbmlNamespace = "http://schemas.microsoft.com/linqtosql/mapping/2007";\r
168 \r
169             public void ReadEmptyContent(XmlReader r, string name)\r
170             {\r
171                 if (r.IsEmptyElement)\r
172                     r.ReadStartElement(name, DbmlNamespace);\r
173                 else\r
174                 {\r
175                     r.ReadStartElement(name, DbmlNamespace);\r
176                     for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())\r
177                     {\r
178                         if (r.NamespaceURI != DbmlNamespace)\r
179                             r.Skip();\r
180                         throw UnexpectedItemError(r);\r
181                     }\r
182                     r.ReadEndElement();\r
183                 }\r
184             }\r
185             public bool GetBooleanAttribute(XmlReader r, string attributeName)\r
186             {\r
187                 return r.GetAttribute(attributeName) == "true";\r
188             }\r
189             public UpdateCheck GetUpdateCheckAttribute(XmlReader r, string attributeName)\r
190             {\r
191                 var s = r.GetAttribute(attributeName);\r
192                 return s != null ? (UpdateCheck)Enum.Parse(typeof(UpdateCheck), s) : default(UpdateCheck);\r
193             }\r
194             public AutoSync GetAutoSyncAttribute(XmlReader r, string attributeName)\r
195             {\r
196                 var s = r.GetAttribute(attributeName);\r
197                 return s != null ? (AutoSync)Enum.Parse(typeof(AutoSync), s) : default(AutoSync);\r
198             }\r
199             public T GetEnumAttribute<T>(XmlReader r, string attributeName)\r
200             {\r
201                 var s = r.GetAttribute(attributeName);\r
202                 return s != null ? (T)Enum.Parse(typeof(T), s) : default(T);\r
203             }\r
204             public XmlException UnexpectedItemError(XmlReader r)\r
205             {\r
206                 return new XmlException(String.Format("Unexpected dbml element '{0}'", r.LocalName));\r
207             }\r
208         }\r
209         class DbmlDatabase : DbmlItem\r
210         {\r
211             public string Name;\r
212             public string Provider;\r
213             public List<DbmlTable> Tables = new List<DbmlTable>();\r
214             public List<DbmlFunction> Functions = new List<DbmlFunction>();\r
215 \r
216             public DbmlDatabase(XmlReader r)\r
217             {\r
218                 r.MoveToContent();\r
219                 Name = r.GetAttribute("Name");\r
220                 Provider = r.GetAttribute("Provider");\r
221                 if (r.IsEmptyElement)\r
222                     r.ReadStartElement("Database", DbmlNamespace);\r
223                 else\r
224                 {\r
225                     r.ReadStartElement("Database", DbmlNamespace);\r
226                     for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())\r
227                     {\r
228                         if (r.NamespaceURI != DbmlNamespace)\r
229                             r.Skip();\r
230                         else\r
231                         {\r
232                             switch (r.LocalName)\r
233                             {\r
234                                 case "Table":\r
235                                     Tables.Add(new DbmlTable(r));\r
236                                     break;\r
237                                 case "Function":\r
238                                     Functions.Add(new DbmlFunction(r));\r
239                                     break;\r
240                                 default:\r
241                                     throw UnexpectedItemError(r);\r
242                             }\r
243                         }\r
244                     }\r
245                     r.ReadEndElement();\r
246                 }\r
247             }\r
248         }\r
249         class DbmlTable : DbmlItem\r
250         {\r
251             public DbmlType Type;\r
252             public string Name;\r
253             public string Member;\r
254 \r
255             public DbmlTable(XmlReader r)\r
256             {\r
257                 Name = r.GetAttribute("Name");\r
258                 Member = r.GetAttribute("Member");\r
259                 if (r.IsEmptyElement)\r
260                     r.ReadStartElement("Table", DbmlNamespace);\r
261                 else\r
262                 {\r
263                     r.ReadStartElement("Table", DbmlNamespace);\r
264                     for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())\r
265                     {\r
266                         if (r.NamespaceURI != DbmlNamespace)\r
267                             r.Skip();\r
268                         else\r
269                         {\r
270                             switch (r.LocalName)\r
271                             {\r
272                                 case "Type":\r
273                                     Type = new DbmlType(r);\r
274                                     break;\r
275                                 default:\r
276                                     throw UnexpectedItemError(r);\r
277                             }\r
278                         }\r
279                     }\r
280                     r.ReadEndElement();\r
281                 }\r
282             }\r
283         }\r
284         class DbmlType : DbmlItem\r
285         {\r
286             public List<DbmlColumn> Columns = new List<DbmlColumn>();\r
287             public List<DbmlAssociation> Associations = new List<DbmlAssociation>();\r
288             public List<DbmlType> Types = new List<DbmlType>();\r
289             public string Name;\r
290             public string InheritanceCode;\r
291             public bool IsInheritanceDefault;\r
292 \r
293             public DbmlType(XmlReader r)\r
294             {\r
295                 Name = r.GetAttribute("Name");\r
296                 InheritanceCode = r.GetAttribute("InheritanceCode");\r
297                 IsInheritanceDefault = GetBooleanAttribute(r, "IsInheritanceDefault");\r
298                 if (r.IsEmptyElement)\r
299                     r.ReadStartElement("Type", DbmlNamespace);\r
300                 else\r
301                 {\r
302                     r.ReadStartElement("Type", DbmlNamespace);\r
303                     for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())\r
304                     {\r
305                         if (r.NamespaceURI != DbmlNamespace)\r
306                             r.Skip();\r
307                         else\r
308                         {\r
309                             switch (r.LocalName)\r
310                             {\r
311                                 case "Column":\r
312                                     Columns.Add(new DbmlColumn(r));\r
313                                     break;\r
314                                 case "Association":\r
315                                     Associations.Add(new DbmlAssociation(r));\r
316                                     break;\r
317                                 case "Type":\r
318                                     Types.Add(new DbmlType(r));\r
319                                     break;\r
320                                 default:\r
321                                     throw UnexpectedItemError(r);\r
322                             }\r
323                         }\r
324                     }\r
325                     r.ReadEndElement();\r
326                 }\r
327             }\r
328         }\r
329 \r
330         class DbmlMemberBase : DbmlItem\r
331         {\r
332             public string Name;\r
333             public string Member;\r
334             public string Storage;\r
335         }\r
336 \r
337         class DbmlColumn : DbmlMemberBase\r
338         {\r
339             public string DbType;\r
340             public bool IsPrimaryKey;\r
341             public bool IsDbGenerated;\r
342             public bool CanBeNull;\r
343             public System.Data.Linq.Mapping.UpdateCheck UpdateCheck;\r
344             public bool IsDiscriminator;\r
345             public string Expression;\r
346             public bool IsVersion;\r
347             public System.Data.Linq.Mapping.AutoSync AutoSync;\r
348 \r
349             public DbmlColumn(XmlReader r)\r
350             {\r
351                 Member = r.GetAttribute("Member");\r
352                 Name = r.GetAttribute("Name") ?? Member;\r
353                 Storage = r.GetAttribute("Storage");\r
354                 DbType = r.GetAttribute("DbType");\r
355                 IsPrimaryKey = GetBooleanAttribute(r, "IsPrimaryKey");\r
356                 IsDbGenerated = GetBooleanAttribute(r, "IsDbGenerated");\r
357                 CanBeNull = GetBooleanAttribute(r, "CanBeNull");\r
358                 UpdateCheck = GetEnumAttribute<System.Data.Linq.Mapping.UpdateCheck>(r, "UpdateCheck");\r
359                 IsDiscriminator = GetBooleanAttribute(r, "IsDiscriminator");\r
360                 Expression = r.GetAttribute("Expression");\r
361                 IsVersion = GetBooleanAttribute(r, "IsVersion");\r
362                 AutoSync = GetEnumAttribute<System.Data.Linq.Mapping.AutoSync>(r, "AutoSync");\r
363                 ReadEmptyContent(r, "Column");\r
364             }\r
365         }\r
366         class DbmlAssociation : DbmlMemberBase\r
367         {\r
368             public string ThisKey;\r
369             public string OtherKey;\r
370             public bool IsForeignKey;\r
371             public bool IsUnique;\r
372             public string DeleteRule;\r
373             public bool DeleteOnNull;\r
374 \r
375             public DbmlAssociation(XmlReader r)\r
376             {\r
377                 Name = r.GetAttribute("Name");\r
378                 Member = r.GetAttribute("Member");\r
379                 Storage = r.GetAttribute("Storage");\r
380                 ThisKey = r.GetAttribute("ThisKey");\r
381                 OtherKey = r.GetAttribute("OtherKey");\r
382                 IsForeignKey = GetBooleanAttribute(r, "IsForeignKey");\r
383                 IsUnique = GetBooleanAttribute(r, "IsUnique");\r
384                 DeleteRule = r.GetAttribute("DeleteRule");\r
385                 DeleteOnNull = GetBooleanAttribute(r, "DeleteOnNull");\r
386                 ReadEmptyContent(r, "Association");\r
387             }\r
388         }\r
389         class DbmlFunction : DbmlItem\r
390         {\r
391             public string Name;\r
392             public string Method;\r
393             public bool IsComposable;\r
394             public List<DbmlParameter> Parameters = new List<DbmlParameter>();\r
395             public List<DbmlType> ElementTypes = new List<DbmlType>();\r
396             public DbmlReturn Return;\r
397 \r
398             public DbmlFunction(XmlReader r)\r
399             {\r
400                 Name = r.GetAttribute("Name");\r
401                 Method = r.GetAttribute("Method");\r
402                 IsComposable = GetBooleanAttribute(r, "IsComposable");\r
403                 if (r.IsEmptyElement)\r
404                     r.ReadStartElement("Function", DbmlNamespace);\r
405                 else\r
406                 {\r
407                     r.ReadStartElement("Function", DbmlNamespace);\r
408                     for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())\r
409                     {\r
410                         if (r.NamespaceURI != DbmlNamespace)\r
411                             r.Skip();\r
412                         else\r
413                         {\r
414                             switch (r.LocalName)\r
415                             {\r
416                                 case "Parameter":\r
417                                     Parameters.Add(new DbmlParameter(r));\r
418                                     break;\r
419                                 case "ElementType":\r
420                                     ElementTypes.Add(new DbmlType(r));\r
421                                     break;\r
422                                 case "Return":\r
423                                     Return = new DbmlReturn(r);\r
424                                     break;\r
425                                 default:\r
426                                     throw UnexpectedItemError(r);\r
427                             }\r
428                         }\r
429                     }\r
430                     r.ReadEndElement();\r
431                 }\r
432             }\r
433         }\r
434         class DbmlParameter : DbmlItem\r
435         {\r
436             public string Name;\r
437             public string Parameter;\r
438             public string DbType;\r
439             public ParameterDirection Direction;\r
440 \r
441             public DbmlParameter(XmlReader r)\r
442             {\r
443                 Name = r.GetAttribute("Name");\r
444                 Parameter = r.GetAttribute("Parameter");\r
445                 DbType = r.GetAttribute("DbType");\r
446                 Direction = GetEnumAttribute<ParameterDirection>(r, "Direction");\r
447                 ReadEmptyContent(r, "Parameter");\r
448             }\r
449         }\r
450         class DbmlReturn : DbmlItem\r
451         {\r
452             public string DbType;\r
453 \r
454             public DbmlReturn(XmlReader r)\r
455             {\r
456                 DbType = r.GetAttribute("DbType");\r
457                 ReadEmptyContent(r, "Return");\r
458             }\r
459         }\r
460 \r
461         class XmlMetaModel : System.Data.Linq.Mapping.MetaModel\r
462         {\r
463             System.Data.Linq.Mapping.MappingSource source;\r
464             DbmlDatabase d;\r
465             System.Type context_type;\r
466             System.Data.Linq.Mapping.MetaFunction[] functions;\r
467             System.Data.Linq.Mapping.MetaTable[] tables;\r
468             Dictionary<System.Type, XmlMetaType> types;\r
469 \r
470             public XmlMetaModel(System.Data.Linq.Mapping.MappingSource source, DbmlDatabase database, System.Type contextType)\r
471             {\r
472                 this.source = source;\r
473                 this.d = database;\r
474                 this.context_type = contextType;\r
475                 RegisterTypes();\r
476             }\r
477 \r
478             void RegisterTypes()\r
479             {\r
480                 types = new Dictionary<System.Type, XmlMetaType>();\r
481                 foreach (var t in d.Tables)\r
482                     RegisterTypeAndDescendants(t.Type);\r
483             }\r
484 \r
485             void RegisterTypeAndDescendants(DbmlType dt)\r
486             {\r
487 \r
488                 System.Type t = GetTypeFromName(dt.Name);\r
489                 if (t == null)\r
490                     throw new ArgumentException(String.Format("type '{0}' not found", dt.Name));\r
491                 if (types.ContainsKey(t))\r
492                     return;\r
493                 types.Add(t, new XmlMetaType(this, dt));\r
494                 foreach (var cdt in dt.Types)\r
495                     RegisterTypeAndDescendants(cdt);\r
496             }\r
497 \r
498             public override System.Type ContextType\r
499             {\r
500                 get { return context_type; }\r
501             }\r
502 \r
503             public override string DatabaseName\r
504             {\r
505                 get { return d.Name; }\r
506             }\r
507 \r
508             public override System.Data.Linq.Mapping.MappingSource MappingSource\r
509             {\r
510                 get { return source; }\r
511             }\r
512 \r
513             public override System.Type ProviderType\r
514             {\r
515                 get { return GetTypeFromName(d.Provider); }\r
516             }\r
517 \r
518             public override System.Data.Linq.Mapping.MetaFunction GetFunction(MethodInfo method)\r
519             {\r
520                 foreach (var f in GetFunctions())\r
521                     if (f.Method == method)\r
522                         return f;\r
523                 throw new ArgumentException(String.Format("Corresponding MetaFunction for method '{0}' was not found", method));\r
524             }\r
525 \r
526             public override IEnumerable<System.Data.Linq.Mapping.MetaFunction> GetFunctions()\r
527             {\r
528                 if (functions == null)\r
529                 {\r
530                     var l = new List<System.Data.Linq.Mapping.MetaFunction>();\r
531                     foreach (var f in d.Functions)\r
532                         l.Add(new XmlMetaFunction(this, f));\r
533                     functions = l.ToArray();\r
534                 }\r
535                 return functions;\r
536             }\r
537 \r
538             public System.Type GetTypeFromName(string name)\r
539             {\r
540                 string ns = context_type.Namespace;\r
541                 string full = !name.Contains('.') && !String.IsNullOrEmpty(ns) ? String.Concat(ns, ".", name) : name;\r
542                 var t = this.context_type.Assembly.GetType(full) ?? System.Type.GetType(full);\r
543                 if (t == null)\r
544                     throw new ArgumentException(String.Format("Type '{0}' was not found", full));\r
545                 return t;\r
546             }\r
547 \r
548             public override System.Data.Linq.Mapping.MetaType GetMetaType(System.Type type)\r
549             {\r
550                 if (!types.ContainsKey(type))\r
551                     throw new ArgumentException(String.Format("Type '{0}' is not found in the mapping", type));\r
552                 return types[type];\r
553             }\r
554 \r
555             public override System.Data.Linq.Mapping.MetaTable GetTable(System.Type rowType)\r
556             {\r
557                 foreach (var t in GetTables())\r
558                     if (t.RowType.Type == rowType)\r
559                         return t;\r
560                 //throw new ArgumentException(String.Format("Corresponding MetaTable for row type '{0}' was not found", rowType));\r
561                 return null;\r
562             }\r
563 \r
564             public override IEnumerable<System.Data.Linq.Mapping.MetaTable> GetTables()\r
565             {\r
566                 if (tables == null)\r
567                 {\r
568                     var l = new List<System.Data.Linq.Mapping.MetaTable>();\r
569                     foreach (var t in d.Tables)\r
570                         l.Add(new XmlMetaTable(this, t));\r
571                     tables = l.ToArray();\r
572                 }\r
573                 return tables;\r
574             }\r
575         }\r
576 \r
577         class XmlMetaParameter : System.Data.Linq.Mapping.MetaParameter\r
578         {\r
579             string dbtype, mapped_name;\r
580             ParameterInfo pi;\r
581 \r
582             public XmlMetaParameter(DbmlParameter p, ParameterInfo parameterInfo)\r
583                 : this(p.DbType, p.Parameter, parameterInfo)\r
584             {\r
585             }\r
586 \r
587             public XmlMetaParameter(string dbType, string mappedName, ParameterInfo parameterInfo)\r
588             {\r
589                 this.dbtype = dbType;\r
590                 this.mapped_name = mappedName;\r
591                 this.pi = parameterInfo;\r
592             }\r
593 \r
594             public override string DbType { get { return dbtype; } }\r
595             public override string MappedName { get { return mapped_name; } }\r
596             public override string Name { get { return Parameter.Name; } }\r
597             public override ParameterInfo Parameter { get { return pi; } }\r
598             public override System.Type ParameterType { get { return pi.ParameterType; } }\r
599         }\r
600 \r
601         class XmlMetaTable : System.Data.Linq.Mapping.MetaTable\r
602         {\r
603             public XmlMetaTable(XmlMetaModel model, DbmlTable table)\r
604             {\r
605                 this.model = model;\r
606                 this.t = table;\r
607                 System.Type rt;\r
608                 if (t.Member != null)\r
609                 {\r
610                     foreach (var member in model.ContextType.GetMember(t.Member))\r
611                     {\r
612                         if (table_member != null)\r
613                             throw new ArgumentException(String.Format("The context type '{0}' contains non-identical member '{1}'", model.ContextType, t.Member));\r
614                         table_member = member;\r
615                     }\r
616                     if (table_member == null)\r
617                         table_member = GetFieldsAndProperties(model.ContextType).First(pi => pi.GetMemberType().IsGenericType &&\r
618                             pi.GetMemberType().GetGenericTypeDefinition() == typeof(Table<>) &&\r
619                             pi.GetMemberType().GetGenericArguments()[0] == model.GetTypeFromName(t.Type.Name));\r
620                     if (table_member == null)\r
621                         throw new ArgumentException(String.Format("The context type '{0}' does not contain member '{1}' which is specified in dbml", model.ContextType, t.Member));\r
622                     member_type = table_member.GetMemberType();\r
623                     if (member_type.GetGenericTypeDefinition() != typeof(Table<>))\r
624                         throw new ArgumentException(String.Format("The table member type was unexpected: '{0}'", member_type));\r
625                     rt = member_type.GetGenericArguments()[0];\r
626                 }\r
627                 else\r
628                 {\r
629                     rt = System.Type.GetType(t.Type.Name);\r
630                 }\r
631                 row_type = model.GetMetaType(rt);\r
632                 if (row_type == null)\r
633                     throw new ArgumentException(String.Format("MetaType for '{0}' was not found", rt));\r
634             }\r
635             static IEnumerable<MemberInfo> GetFieldsAndProperties(System.Type type)\r
636             {\r
637                 foreach (var f in type.GetFields())\r
638                     yield return f;\r
639                 foreach (var p in type.GetProperties())\r
640                     yield return p;\r
641             }\r
642 \r
643             XmlMetaModel model;\r
644             DbmlTable t;\r
645             MemberInfo table_member;\r
646             System.Type member_type;\r
647             System.Data.Linq.Mapping.MetaType row_type;\r
648 \r
649             [DbLinqToDo]\r
650             public override MethodInfo DeleteMethod\r
651             {\r
652                 get { throw new NotImplementedException(); }\r
653             }\r
654             [DbLinqToDo]\r
655             public override MethodInfo InsertMethod\r
656             {\r
657                 get { throw new NotImplementedException(); }\r
658             }\r
659             public override System.Data.Linq.Mapping.MetaModel Model { get { return model; } }\r
660             public override System.Data.Linq.Mapping.MetaType RowType { get { return row_type; } }\r
661             System.Type MemberType { get { return member_type; } }\r
662             public override string TableName { get { return t.Name; } }\r
663             [DbLinqToDo]\r
664             public override MethodInfo UpdateMethod\r
665             {\r
666                 get { throw new NotImplementedException(); }\r
667             }\r
668 \r
669             // not used yet\r
670             MethodInfo GetMethod(TableFunction f)\r
671             {\r
672                 if (f == null)\r
673                     return null;\r
674                 foreach (var mf in model.GetFunctions())\r
675                     if (mf.Name == f.FunctionId)\r
676                         return mf.Method;\r
677                 return null;\r
678             }\r
679         }\r
680 \r
681         class XmlMetaType : System.Data.Linq.Mapping.MetaType\r
682         {\r
683             XmlMetaModel model;\r
684             DbmlType t;\r
685             ReadOnlyCollection<System.Data.Linq.Mapping.MetaAssociation> associations;\r
686             System.Type runtime_type;\r
687             ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember> members, identity_members, persistent_members;\r
688 \r
689             public XmlMetaType(XmlMetaModel model, DbmlType type)\r
690             {\r
691                 this.model = model;\r
692                 this.t = type;\r
693                 runtime_type = model.GetTypeFromName(t.Name);\r
694                 int i = 0;\r
695                 var l = new List<System.Data.Linq.Mapping.MetaDataMember>();\r
696                 l.AddRange(Array.ConvertAll<DbmlColumn, System.Data.Linq.Mapping.MetaDataMember>(\r
697                     t.Columns.ToArray(), c => new XmlColumnMetaDataMember(model, this, c, i++)));\r
698                 members = new ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember>(l);\r
699             }\r
700 \r
701             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaAssociation> Associations\r
702             {\r
703                 get\r
704                 {\r
705                     if (associations == null)\r
706                     {\r
707                         var l = new List<System.Data.Linq.Mapping.MetaAssociation>();\r
708                         // FIXME: Ordinal?\r
709                         foreach (var a in t.Associations)\r
710                             l.Add(new XmlMetaAssociation(this, new XmlAssociationMetaDataMember(model, this, a, -1), a));\r
711                         associations = new ReadOnlyCollection<System.Data.Linq.Mapping.MetaAssociation>(l.ToArray());\r
712                     }\r
713                     return associations;\r
714                 }\r
715             }\r
716             public override bool CanInstantiate { get { return !runtime_type.IsAbstract; } }\r
717             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember> DataMembers { get { return members; } }\r
718             public override System.Data.Linq.Mapping.MetaDataMember DBGeneratedIdentityMember\r
719             {\r
720                 get { return members.First(m => m.IsDbGenerated && m.IsPrimaryKey); }\r
721             }\r
722             [DbLinqToDo]\r
723             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaType> DerivedTypes\r
724             {\r
725                 get { throw new NotImplementedException(); }\r
726             }\r
727             public override System.Data.Linq.Mapping.MetaDataMember Discriminator\r
728             {\r
729                 get { return members.First(m => m.IsDiscriminator); }\r
730             }\r
731             public override bool HasAnyLoadMethod\r
732             {\r
733                 get { return members.Any(m => m.LoadMethod != null); }\r
734             }\r
735             [DbLinqToDo]\r
736             public override bool HasAnyValidateMethod\r
737             {\r
738                 get { throw new NotImplementedException(); }\r
739             }\r
740             [DbLinqToDo]\r
741             public override bool HasInheritance\r
742             {\r
743                 get { throw new NotImplementedException(); }\r
744             }\r
745             public override bool HasInheritanceCode\r
746             {\r
747                 get { return t.InheritanceCode != null; }\r
748             }\r
749             public override bool HasUpdateCheck { get { return members.Any(m => m.UpdateCheck != System.Data.Linq.Mapping.UpdateCheck.Never); } }\r
750             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember> IdentityMembers\r
751             {\r
752                 get\r
753                 {\r
754                     if (identity_members == null)\r
755                     {\r
756                         identity_members = new ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember>(\r
757                             members.TakeWhile(m => m.IsPrimaryKey).ToArray());\r
758                     }\r
759                     return identity_members;\r
760                 }\r
761             }\r
762             [DbLinqToDo]\r
763             public override System.Data.Linq.Mapping.MetaType InheritanceBase\r
764             {\r
765                 get { throw new NotImplementedException(); }\r
766             }\r
767             public override Object InheritanceCode { get { return t.InheritanceCode; } }\r
768             [DbLinqToDo]\r
769             public override System.Data.Linq.Mapping.MetaType InheritanceDefault\r
770             {\r
771                 get { throw new NotImplementedException(); }\r
772             }\r
773             [DbLinqToDo]\r
774             public override System.Data.Linq.Mapping.MetaType InheritanceRoot\r
775             {\r
776                 get { throw new NotImplementedException(); }\r
777             }\r
778             [DbLinqToDo]\r
779             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaType> InheritanceTypes\r
780             {\r
781                 get { throw new NotImplementedException(); }\r
782             }\r
783             [DbLinqToDo]\r
784             public override bool IsEntity { get { return true; } }\r
785             public override bool IsInheritanceDefault { get { return t.IsInheritanceDefault; } }\r
786             public override System.Data.Linq.Mapping.MetaModel Model { get { return model; } }\r
787             public override string Name { get { return t.Name; } }\r
788             [DbLinqToDo]\r
789             public override MethodInfo OnLoadedMethod\r
790             {\r
791                 get { throw new NotImplementedException(); }\r
792             }\r
793             [DbLinqToDo]\r
794             public override MethodInfo OnValidateMethod\r
795             {\r
796                 get { throw new NotImplementedException(); }\r
797             }\r
798             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember> PersistentDataMembers\r
799             {\r
800                 get\r
801                 {\r
802                     if (persistent_members == null)\r
803                     {\r
804                         persistent_members = new ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember>(\r
805                             members.TakeWhile(m => m.IsPersistent).ToArray());\r
806                     }\r
807                     return persistent_members;\r
808                 }\r
809             }\r
810             public override System.Data.Linq.Mapping.MetaTable Table { get { return model.GetTable(runtime_type); } }\r
811             public override System.Type Type { get { return runtime_type; } }\r
812             public override System.Data.Linq.Mapping.MetaDataMember VersionMember { get { return members.First(m => m.IsVersion); } }\r
813 \r
814             public override System.Data.Linq.Mapping.MetaDataMember GetDataMember(MemberInfo member)\r
815             {\r
816                 //return members.First(m => m.Member == member);\r
817                 foreach (var m in members) \r
818                     if (m.Member == member || (m.Member.ToString() == member.ToString() && member.DeclaringType.IsAssignableFrom(m.Member.DeclaringType))) \r
819                         return m;\r
820                 throw new ArgumentException(String.Format("No corresponding metadata member for '{0}'", member));\r
821             }\r
822 \r
823             public override System.Data.Linq.Mapping.MetaType GetInheritanceType(System.Type type)\r
824             {\r
825                 return InheritanceTypes.First(t => t.Type == type);\r
826             }\r
827 \r
828             [DbLinqToDo]\r
829             public override System.Data.Linq.Mapping.MetaType GetTypeForInheritanceCode(object code)\r
830             {\r
831                 throw new NotImplementedException();\r
832             }\r
833         }\r
834 \r
835         class XmlMetaAssociation : System.Data.Linq.Mapping.MetaAssociation\r
836         {\r
837             //XmlMetaType owner;\r
838             DbmlAssociation a;\r
839             ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember> these_keys, other_keys;\r
840             System.Data.Linq.Mapping.MetaDataMember member;\r
841 \r
842             public XmlMetaAssociation(XmlMetaType owner, XmlMetaDataMember member, DbmlAssociation a)\r
843             {\r
844                 //this.owner = owner;\r
845                 this.member = member;\r
846                 this.a = a;\r
847                 SetupRelationship();\r
848             }\r
849 \r
850             /// <summary>\r
851             /// This function sets up the relationship information based on the attribute <see cref="XmlMetaModel"/>.\r
852             /// </summary>\r
853             private void SetupRelationship()\r
854             {\r
855                 //Get the association target type\r
856                 System.Type targetType = member.Member.GetFirstInnerReturnType();\r
857 \r
858                 var metaModel = ThisMember.DeclaringType.Model as XmlMetaModel;\r
859                 if (metaModel == null)\r
860                 {\r
861                     throw new InvalidOperationException("Internal Error: MetaModel is not a XmlMetaModel");\r
862                 }\r
863 \r
864                 System.Data.Linq.Mapping.MetaTable otherTable = metaModel.GetTable(targetType);\r
865 \r
866                 //Setup "this key"\r
867                 these_keys = GetKeys(a.ThisKey ?? String.Empty, ThisMember.DeclaringType);\r
868 \r
869                 //Setup other key\r
870                 other_keys = GetKeys(a.OtherKey ?? String.Empty, otherTable.RowType);\r
871             }\r
872 \r
873             //Seperator used for key lists\r
874             private static readonly char[] STRING_SEPERATOR = new[] { ',' };\r
875 \r
876             /// <summary>\r
877             /// Returns a list of keys from the given meta type based on the key list string.\r
878             /// </summary>\r
879             /// <param name="keyListString">The key list string.</param>\r
880             /// <param name="parentType">Type of the parent.</param>\r
881             /// <returns></returns>\r
882             private static ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember> GetKeys(string keyListString, System.Data.Linq.Mapping.MetaType parentType)\r
883             {\r
884                 if (keyListString != null)\r
885                 {\r
886                     var thisKeyList = new List<System.Data.Linq.Mapping.MetaDataMember>();\r
887 \r
888                     string[] keyNames = keyListString.Split(STRING_SEPERATOR, StringSplitOptions.RemoveEmptyEntries);\r
889 \r
890                     foreach (string rawKeyName in keyNames)\r
891                     {\r
892                         string keyName = rawKeyName.Trim();\r
893 \r
894                         //TODO: maybe speed the lookup up\r
895                         System.Data.Linq.Mapping.MetaDataMember key = (from dataMember in parentType.PersistentDataMembers\r
896                                               where dataMember.Name == keyName\r
897                                               select dataMember).SingleOrDefault();\r
898 \r
899                         if (key == null)\r
900                         {\r
901                             string errorMessage = string.Format("Could not find key member '{0}' of key '{1}' on type '{2}'. The key may be wrong or the field or property on '{2}' has changed names.",\r
902                                 keyName, keyListString, parentType.Type.Name);\r
903 \r
904                             throw new InvalidOperationException(errorMessage);\r
905                         }\r
906 \r
907                         thisKeyList.Add(key);\r
908                     }\r
909 \r
910                     return new ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember>(thisKeyList);\r
911                 }\r
912                 else //Key is the primary key of this table\r
913                 {\r
914                     return parentType.IdentityMembers;\r
915                 }\r
916             }\r
917 \r
918             public override bool DeleteOnNull { get { return a.DeleteOnNull; } }\r
919             public override string DeleteRule { get { return a.DeleteRule; } }\r
920             public override bool IsForeignKey { get { return a.IsForeignKey; } }\r
921             [DbLinqToDo]\r
922             public override bool IsMany\r
923             {\r
924                 get { throw new NotImplementedException(); }\r
925             }\r
926             public override bool IsNullable { get { return member.Member.GetMemberType().IsNullable(); } }\r
927             public override bool IsUnique { get { return a.IsUnique; } }\r
928             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember> OtherKey { get { return other_keys; } }\r
929             public override bool OtherKeyIsPrimaryKey { get { return OtherKey.All(m => m.IsPrimaryKey); } }\r
930             [DbLinqToDo]\r
931             public override System.Data.Linq.Mapping.MetaDataMember OtherMember\r
932             {\r
933                 get { throw new NotImplementedException(); }\r
934             }\r
935             public override System.Data.Linq.Mapping.MetaType OtherType { get { return OtherMember.DeclaringType; } }\r
936             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaDataMember> ThisKey { get { return these_keys; } }\r
937             public override bool ThisKeyIsPrimaryKey { get { return ThisKey.All(m => m.IsPrimaryKey); } }\r
938             public override System.Data.Linq.Mapping.MetaDataMember ThisMember { get { return member; } }\r
939         }\r
940 \r
941         abstract class XmlMetaDataMember : System.Data.Linq.Mapping.MetaDataMember\r
942         {\r
943             internal XmlMetaModel model;\r
944             internal XmlMetaType type;\r
945             internal MemberInfo member, storage;\r
946             System.Data.Linq.Mapping.MetaAccessor member_accessor, storage_accessor;\r
947             int ordinal;\r
948 \r
949             protected XmlMetaDataMember(XmlMetaModel model, XmlMetaType type, string memberName, string storageName, int ordinal)\r
950             {\r
951                 this.model = model;\r
952                 this.type = type;\r
953                 BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;\r
954                 if (type.Type.GetMember(memberName, bf).Length == 0)\r
955                     throw new ArgumentException(String.Format("Specified member '{0}' was not found in type '{1}'", memberName, type.Name));\r
956                 if (type.Type.GetMember(storageName, bf).Length == 0)\r
957                     throw new ArgumentException(String.Format("Specified member '{0}' was not found in type '{1}'", storageName, type.Name));\r
958                 this.member = type.Type.GetMember(memberName, bf)[0];\r
959                 this.storage = type.Type.GetMember(storageName, bf)[0];\r
960                 this.ordinal = ordinal;\r
961             }\r
962 \r
963             public override bool CanBeNull { get { return member.GetMemberType().IsNullable(); } }\r
964             public override System.Data.Linq.Mapping.MetaType DeclaringType { get { return type; } }\r
965             public override bool IsDeferred { get { return false; } }\r
966             public override bool IsPersistent { get { return true; } }\r
967             public override MemberInfo Member { get { return member; } }\r
968             public override System.Data.Linq.Mapping.MetaAccessor MemberAccessor\r
969             {\r
970                 get\r
971                 {\r
972                     if (member_accessor == null)\r
973                         member_accessor = new XmlMetaAccessor(this, Member);\r
974                     return member_accessor;\r
975                 }\r
976             }\r
977             public override int Ordinal { get { return ordinal; } }\r
978             public override System.Data.Linq.Mapping.MetaAccessor StorageAccessor\r
979             {\r
980                 get\r
981                 {\r
982                     if (storage_accessor == null)\r
983                         storage_accessor = new XmlMetaAccessor(this, StorageMember);\r
984                     return storage_accessor;\r
985                 }\r
986             }\r
987             public override MemberInfo StorageMember { get { return storage; } }\r
988             public override System.Type Type { get { return member.GetMemberType(); } }\r
989 \r
990             public override bool IsDeclaredBy(System.Data.Linq.Mapping.MetaType type)\r
991             {\r
992                 return this.type == type;\r
993             }\r
994         }\r
995 \r
996         class XmlColumnMetaDataMember : XmlMetaDataMember\r
997         {\r
998             DbmlColumn c;\r
999 \r
1000             public XmlColumnMetaDataMember(XmlMetaModel model, XmlMetaType type, DbmlColumn column, int ordinal)\r
1001                 : base(model, type, column.Member, column.Storage, ordinal)\r
1002             {\r
1003                 this.c = column;\r
1004             }\r
1005 \r
1006             public override System.Data.Linq.Mapping.MetaAssociation Association { get { return null; } }\r
1007             public override System.Data.Linq.Mapping.AutoSync AutoSync { get { return (System.Data.Linq.Mapping.AutoSync)c.AutoSync; } }\r
1008             public override string DbType { get { return c.DbType; } }\r
1009             [DbLinqToDo]\r
1010             public override System.Data.Linq.Mapping.MetaAccessor DeferredSourceAccessor\r
1011             {\r
1012                 get { throw new NotImplementedException(); }\r
1013             }\r
1014             [DbLinqToDo]\r
1015             public override System.Data.Linq.Mapping.MetaAccessor DeferredValueAccessor\r
1016             {\r
1017                 get { throw new NotImplementedException(); }\r
1018             }\r
1019 \r
1020             public override string Expression { get { return c.Expression; } }\r
1021             public override bool IsAssociation { get { return false; } }\r
1022             public override bool IsDbGenerated { get { return c.IsDbGenerated; } }\r
1023             public override bool IsDiscriminator { get { return c.IsDiscriminator; } }\r
1024             public override bool IsPrimaryKey { get { return c.IsPrimaryKey; } }\r
1025             public override bool IsVersion { get { return c.IsVersion; } }\r
1026             [DbLinqToDo]\r
1027             public override MethodInfo LoadMethod\r
1028             {\r
1029                 get\r
1030                 {\r
1031                     throw new NotImplementedException();\r
1032                 }\r
1033             }\r
1034             public override string MappedName { get { return c.Name; } }\r
1035             public override string Name { get { return c.Member ?? c.Name; } }\r
1036             public override System.Data.Linq.Mapping.UpdateCheck UpdateCheck { get { return c.UpdateCheck; } }\r
1037         }\r
1038 \r
1039         class XmlAssociationMetaDataMember : XmlMetaDataMember\r
1040         {\r
1041             DbmlAssociation a;\r
1042             XmlMetaAssociation ma;\r
1043 \r
1044             public XmlAssociationMetaDataMember(XmlMetaModel model, XmlMetaType type, DbmlAssociation association, int ordinal)\r
1045                 : base(model, type, association.Member, association.Storage, ordinal)\r
1046             {\r
1047                 this.a = association;\r
1048             }\r
1049 \r
1050             public override System.Data.Linq.Mapping.MetaAssociation Association\r
1051             {\r
1052                 get\r
1053                 {\r
1054                     if (ma == null)\r
1055                         this.ma = new XmlMetaAssociation(type, this, a);\r
1056                     return ma;\r
1057                 }\r
1058             }\r
1059             public override System.Data.Linq.Mapping.AutoSync AutoSync { get { return System.Data.Linq.Mapping.AutoSync.Never; } }\r
1060             public override string DbType { get { return String.Empty; } }\r
1061             [DbLinqToDo]\r
1062             public override System.Data.Linq.Mapping.MetaAccessor DeferredSourceAccessor\r
1063             {\r
1064                 get { throw new NotImplementedException(); }\r
1065             }\r
1066             [DbLinqToDo]\r
1067             public override System.Data.Linq.Mapping.MetaAccessor DeferredValueAccessor\r
1068             {\r
1069                 get { throw new NotImplementedException(); }\r
1070             }\r
1071 \r
1072             public override string Expression { get { return String.Empty; } }\r
1073             public override bool IsAssociation { get { return true; } }\r
1074             public override bool IsDbGenerated { get { return false; } }\r
1075             public override bool IsDiscriminator { get { return false; } }\r
1076             [DbLinqToDo]\r
1077             public override bool IsPrimaryKey\r
1078             {\r
1079                 get { throw new NotImplementedException(); }\r
1080             }\r
1081             [DbLinqToDo]\r
1082             public override bool IsVersion\r
1083             {\r
1084                 get { throw new NotImplementedException(); }\r
1085             }\r
1086             [DbLinqToDo]\r
1087             public override MethodInfo LoadMethod\r
1088             {\r
1089                 get\r
1090                 {\r
1091                     throw new NotImplementedException();\r
1092                 }\r
1093             }\r
1094             public override string MappedName { get { return a.Member; } }\r
1095             public override string Name { get { return a.Name; } }\r
1096             public override System.Data.Linq.Mapping.UpdateCheck UpdateCheck\r
1097             {\r
1098                 get\r
1099                 {\r
1100                     throw new NotImplementedException();\r
1101                 }\r
1102             }\r
1103         }\r
1104 \r
1105         class XmlMetaAccessor : System.Data.Linq.Mapping.MetaAccessor\r
1106         {\r
1107             XmlMetaDataMember member;\r
1108             MemberInfo member_info;\r
1109 \r
1110             public XmlMetaAccessor(XmlMetaDataMember member, MemberInfo memberInfo)\r
1111             {\r
1112                 this.member = member;\r
1113                 this.member_info = memberInfo;\r
1114             }\r
1115 \r
1116             public override System.Type Type\r
1117             {\r
1118                 get { return member_info is FieldInfo ? ((FieldInfo)member_info).FieldType : ((PropertyInfo)member_info).PropertyType; }\r
1119             }\r
1120 \r
1121             [DbLinqToDo]\r
1122             public override object GetBoxedValue(object instance)\r
1123             {\r
1124                 throw new NotImplementedException();\r
1125             }\r
1126 \r
1127             [DbLinqToDo]\r
1128             public override void SetBoxedValue(ref object instance, object value)\r
1129             {\r
1130                 throw new NotImplementedException();\r
1131             }\r
1132         }\r
1133 \r
1134         class XmlMetaFunction : System.Data.Linq.Mapping.MetaFunction\r
1135         {\r
1136             XmlMetaModel model;\r
1137             DbmlFunction f;\r
1138             MethodInfo method;\r
1139             ReadOnlyCollection<System.Data.Linq.Mapping.MetaParameter> parameters;\r
1140             ReadOnlyCollection<System.Data.Linq.Mapping.MetaType> result_types;\r
1141             System.Data.Linq.Mapping.MetaParameter return_param;\r
1142 \r
1143             public XmlMetaFunction(XmlMetaModel model, DbmlFunction function)\r
1144             {\r
1145                 this.model = model;\r
1146                 this.f = function;\r
1147                 method = model.ContextType.GetMethod(function.Method);\r
1148                 return_param = new XmlMetaParameter(function.Return.DbType, String.Empty, method.ReturnParameter);\r
1149             }\r
1150 \r
1151             public override bool HasMultipleResults { get { return f.ElementTypes.Count > 0; } }\r
1152             public override bool IsComposable { get { return f.IsComposable; } }\r
1153             public override string MappedName { get { return f.Name; } }\r
1154             public override MethodInfo Method { get { return method; } }\r
1155             public override System.Data.Linq.Mapping.MetaModel Model { get { return model; } }\r
1156             public override string Name { get { return f.Name; } }\r
1157             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaParameter> Parameters\r
1158             {\r
1159                 get\r
1160                 {\r
1161                     if (parameters == null)\r
1162                     {\r
1163                         var l = new List<System.Data.Linq.Mapping.MetaParameter>();\r
1164                         int i = 0;\r
1165                         ParameterInfo[] mparams = method.GetParameters();\r
1166                         foreach (var p in f.Parameters)\r
1167                             l.Add(new XmlMetaParameter(p, mparams[i++]));\r
1168                         parameters = new ReadOnlyCollection<System.Data.Linq.Mapping.MetaParameter>(l);\r
1169                     }\r
1170                     return parameters;\r
1171                 }\r
1172             }\r
1173             public override ReadOnlyCollection<System.Data.Linq.Mapping.MetaType> ResultRowTypes\r
1174             {\r
1175                 get\r
1176                 {\r
1177                     if (result_types == null)\r
1178                     {\r
1179                         var l = new List<System.Data.Linq.Mapping.MetaType>();\r
1180                         foreach (var p in f.ElementTypes)\r
1181                             l.Add(model.GetMetaType(model.GetTypeFromName(p.Name)));\r
1182                         result_types = new ReadOnlyCollection<System.Data.Linq.Mapping.MetaType>(l.ToArray());\r
1183                     }\r
1184                     return result_types;\r
1185                 }\r
1186             }\r
1187             public override System.Data.Linq.Mapping.MetaParameter ReturnParameter { get { return return_param; } }\r
1188         }\r
1189     }\r
1190 }\r