5 // Copyright (c) 2007-2008 Jiri Moudry, Stefan Klinger
\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
14 // The above copyright notice and this permission notice shall be included in
\r
15 // all copies or substantial portions of the Software.
\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
29 default namespace = "http://schemas.microsoft.com/linqtosql/mapping/2007"
\r
32 start = element Database { Database }
\r
35 element Table { Table }*,
\r
36 element Function { Function }*,
\r
37 attribute Name { text }?,
\r
38 attribute Provider { text }?
\r
42 element Type { Type },
\r
43 attribute Name { text }?,
\r
44 attribute Member { text }?
\r
49 element Column { Column }* |
\r
50 element Association { Association }*
\r
52 element Type { Type }*,
\r
53 attribute Name { text },
\r
54 attribute InheritanceCode { text }?,
\r
55 attribute IsInheritanceDefault { boolean }?
\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
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
86 element Parameter { Parameter }*,
\r
88 element ElementType { Type }* |
\r
89 element Return { Return }
\r
91 attribute Name { text }?,
\r
92 attribute Method { text },
\r
93 attribute IsComposable { boolean }?
\r
97 attribute Name { text }?,
\r
98 attribute Parameter { text },
\r
99 attribute DbType { text }?,
\r
100 attribute Direction { ParameterDirection }?
\r
103 Return = attribute DbType { text}?
\r
105 UpdateCheck = "Always" | "Never" | "WhenChanged"
\r
106 ParameterDirection = "In" | "Out" | "InOut"
\r
107 AutoSync = "Never" | "OnInsert" | "OnUpdate" | "Always" | "Default"
\r
110 ---------------- */
\r
114 using System.Collections.Generic;
\r
115 using System.Collections.ObjectModel;
\r
118 using System.Reflection;
\r
121 using DbLinq.Schema.Dbml;
\r
125 namespace System.Data.Linq.Mapping
\r
127 namespace DbLinq.Data.Linq.Mapping
\r
130 public sealed class XmlMappingSource : MappingSource
\r
134 XmlMappingSource(XmlReader reader)
\r
136 db = new DbmlDatabase(reader);
\r
139 public static XmlMappingSource FromReader(XmlReader reader)
\r
141 return new XmlMappingSource(reader);
\r
144 public static XmlMappingSource FromStream(Stream stream)
\r
146 return FromReader(XmlReader.Create(stream));
\r
149 public static XmlMappingSource FromUrl(string url)
\r
151 return FromReader(XmlReader.Create(url));
\r
154 public static XmlMappingSource FromXml(string xml)
\r
156 return FromReader(XmlReader.Create(new StringReader(xml)));
\r
159 protected override MetaModel CreateModel(Type dataContextType)
\r
161 return new XmlMetaModel(this, db, dataContextType);
\r
165 abstract class DbmlItem
\r
167 public const string DbmlNamespace = "http://schemas.microsoft.com/linqtosql/mapping/2007";
\r
169 public void ReadEmptyContent(XmlReader r, string name)
\r
171 if (r.IsEmptyElement)
\r
172 r.ReadStartElement(name, DbmlNamespace);
\r
175 r.ReadStartElement(name, DbmlNamespace);
\r
176 for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())
\r
178 if (r.NamespaceURI != DbmlNamespace)
\r
180 throw UnexpectedItemError(r);
\r
182 r.ReadEndElement();
\r
185 public bool GetBooleanAttribute(XmlReader r, string attributeName)
\r
187 return r.GetAttribute(attributeName) == "true";
\r
189 public UpdateCheck GetUpdateCheckAttribute(XmlReader r, string attributeName)
\r
191 var s = r.GetAttribute(attributeName);
\r
192 return s != null ? (UpdateCheck)Enum.Parse(typeof(UpdateCheck), s) : default(UpdateCheck);
\r
194 public AutoSync GetAutoSyncAttribute(XmlReader r, string attributeName)
\r
196 var s = r.GetAttribute(attributeName);
\r
197 return s != null ? (AutoSync)Enum.Parse(typeof(AutoSync), s) : default(AutoSync);
\r
199 public T GetEnumAttribute<T>(XmlReader r, string attributeName)
\r
201 var s = r.GetAttribute(attributeName);
\r
202 return s != null ? (T)Enum.Parse(typeof(T), s) : default(T);
\r
204 public XmlException UnexpectedItemError(XmlReader r)
\r
206 return new XmlException(String.Format("Unexpected dbml element '{0}'", r.LocalName));
\r
209 class DbmlDatabase : DbmlItem
\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
216 public DbmlDatabase(XmlReader r)
\r
219 Name = r.GetAttribute("Name");
\r
220 Provider = r.GetAttribute("Provider");
\r
221 if (r.IsEmptyElement)
\r
222 r.ReadStartElement("Database", DbmlNamespace);
\r
225 r.ReadStartElement("Database", DbmlNamespace);
\r
226 for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())
\r
228 if (r.NamespaceURI != DbmlNamespace)
\r
232 switch (r.LocalName)
\r
235 Tables.Add(new DbmlTable(r));
\r
238 Functions.Add(new DbmlFunction(r));
\r
241 throw UnexpectedItemError(r);
\r
245 r.ReadEndElement();
\r
249 class DbmlTable : DbmlItem
\r
251 public DbmlType Type;
\r
252 public string Name;
\r
253 public string Member;
\r
255 public DbmlTable(XmlReader r)
\r
257 Name = r.GetAttribute("Name");
\r
258 Member = r.GetAttribute("Member");
\r
259 if (r.IsEmptyElement)
\r
260 r.ReadStartElement("Table", DbmlNamespace);
\r
263 r.ReadStartElement("Table", DbmlNamespace);
\r
264 for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())
\r
266 if (r.NamespaceURI != DbmlNamespace)
\r
270 switch (r.LocalName)
\r
273 Type = new DbmlType(r);
\r
276 throw UnexpectedItemError(r);
\r
280 r.ReadEndElement();
\r
284 class DbmlType : DbmlItem
\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
293 public DbmlType(XmlReader r)
\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
302 r.ReadStartElement("Type", DbmlNamespace);
\r
303 for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())
\r
305 if (r.NamespaceURI != DbmlNamespace)
\r
309 switch (r.LocalName)
\r
312 Columns.Add(new DbmlColumn(r));
\r
314 case "Association":
\r
315 Associations.Add(new DbmlAssociation(r));
\r
318 Types.Add(new DbmlType(r));
\r
321 throw UnexpectedItemError(r);
\r
325 r.ReadEndElement();
\r
330 class DbmlMemberBase : DbmlItem
\r
332 public string Name;
\r
333 public string Member;
\r
334 public string Storage;
\r
337 class DbmlColumn : DbmlMemberBase
\r
339 public string DbType;
\r
340 public bool IsPrimaryKey;
\r
341 public bool IsDbGenerated;
\r
342 public bool CanBeNull;
\r
343 public UpdateCheck UpdateCheck;
\r
344 public bool IsDiscriminator;
\r
345 public string Expression;
\r
346 public bool IsVersion;
\r
347 public AutoSync AutoSync;
\r
349 public DbmlColumn(XmlReader r)
\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<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<AutoSync>(r, "AutoSync");
\r
363 ReadEmptyContent(r, "Column");
\r
366 class DbmlAssociation : DbmlMemberBase
\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
375 public DbmlAssociation(XmlReader r)
\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
389 class DbmlFunction : DbmlItem
\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
398 public DbmlFunction(XmlReader r)
\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
407 r.ReadStartElement("Function", DbmlNamespace);
\r
408 for (r.MoveToContent(); r.NodeType != XmlNodeType.EndElement; r.MoveToContent())
\r
410 if (r.NamespaceURI != DbmlNamespace)
\r
414 switch (r.LocalName)
\r
417 Parameters.Add(new DbmlParameter(r));
\r
419 case "ElementType":
\r
420 ElementTypes.Add(new DbmlType(r));
\r
423 Return = new DbmlReturn(r);
\r
426 throw UnexpectedItemError(r);
\r
430 r.ReadEndElement();
\r
434 class DbmlParameter : DbmlItem
\r
436 public string Name;
\r
437 public string Parameter;
\r
438 public string DbType;
\r
439 public ParameterDirection Direction;
\r
441 public DbmlParameter(XmlReader r)
\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
450 class DbmlReturn : DbmlItem
\r
452 public string DbType;
\r
454 public DbmlReturn(XmlReader r)
\r
456 DbType = r.GetAttribute("DbType");
\r
457 ReadEmptyContent(r, "Return");
\r
461 class XmlMetaModel : MetaModel
\r
463 MappingSource source;
\r
466 MetaFunction[] functions;
\r
467 MetaTable[] tables;
\r
468 Dictionary<Type, XmlMetaType> types;
\r
470 public XmlMetaModel(MappingSource source, DbmlDatabase database, Type contextType)
\r
472 this.source = source;
\r
474 this.context_type = contextType;
\r
478 void RegisterTypes()
\r
480 types = new Dictionary<Type, XmlMetaType>();
\r
481 foreach (var t in d.Tables)
\r
482 RegisterTypeAndDescendants(t.Type);
\r
485 void RegisterTypeAndDescendants(DbmlType dt)
\r
488 Type t = GetTypeFromName(dt.Name);
\r
490 throw new ArgumentException(String.Format("type '{0}' not found", dt.Name));
\r
491 if (types.ContainsKey(t))
\r
493 types.Add(t, new XmlMetaType(this, dt));
\r
494 foreach (var cdt in dt.Types)
\r
495 RegisterTypeAndDescendants(cdt);
\r
498 public override Type ContextType
\r
500 get { return context_type; }
\r
503 public override string DatabaseName
\r
505 get { return d.Name; }
\r
508 public override MappingSource MappingSource
\r
510 get { return source; }
\r
513 public override Type ProviderType
\r
515 get { return GetTypeFromName(d.Provider); }
\r
518 public override MetaFunction GetFunction(MethodInfo method)
\r
520 foreach (var f in GetFunctions())
\r
521 if (f.Method == method)
\r
523 throw new ArgumentException(String.Format("Corresponding MetaFunction for method '{0}' was not found", method));
\r
526 public override IEnumerable<MetaFunction> GetFunctions()
\r
528 if (functions == null)
\r
530 var l = new List<MetaFunction>();
\r
531 foreach (var f in d.Functions)
\r
532 l.Add(new XmlMetaFunction(this, f));
\r
533 functions = l.ToArray();
\r
538 public Type GetTypeFromName(string name)
\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);
\r
544 throw new ArgumentException(String.Format("Type '{0}' was not found", full));
\r
548 public override MetaType GetMetaType(Type type)
\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
555 public override MetaTable GetTable(Type rowType)
\r
557 foreach (var t in GetTables())
\r
558 if (t.RowType.Type == rowType)
\r
560 //throw new ArgumentException(String.Format("Corresponding MetaTable for row type '{0}' was not found", rowType));
\r
564 public override IEnumerable<MetaTable> GetTables()
\r
566 if (tables == null)
\r
568 var l = new List<MetaTable>();
\r
569 foreach (var t in d.Tables)
\r
570 l.Add(new XmlMetaTable(this, t));
\r
571 tables = l.ToArray();
\r
577 class XmlMetaParameter : MetaParameter
\r
579 string dbtype, mapped_name;
\r
582 public XmlMetaParameter(DbmlParameter p, ParameterInfo parameterInfo)
\r
583 : this(p.DbType, p.Parameter, parameterInfo)
\r
587 public XmlMetaParameter(string dbType, string mappedName, ParameterInfo parameterInfo)
\r
589 this.dbtype = dbType;
\r
590 this.mapped_name = mappedName;
\r
591 this.pi = parameterInfo;
\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 Type ParameterType { get { return pi.ParameterType; } }
\r
601 class XmlMetaTable : MetaTable
\r
603 public XmlMetaTable(XmlMetaModel model, DbmlTable table)
\r
605 this.model = model;
\r
607 foreach (var member in model.ContextType.GetMember(t.Member))
\r
609 if (table_member != null)
\r
610 throw new ArgumentException(String.Format("The context type '{0}' contains non-identical member '{1}'", model.ContextType, t.Member));
\r
611 table_member = member;
\r
613 if (table_member == null)
\r
614 table_member = GetFieldsAndProperties(model.ContextType).First(pi => pi.GetMemberType().IsGenericType &&
\r
615 pi.GetMemberType().GetGenericTypeDefinition() == typeof(Table<>) &&
\r
616 pi.GetMemberType().GetGenericArguments()[0] == model.GetTypeFromName(t.Type.Name));
\r
617 if (table_member == null)
\r
618 throw new ArgumentException(String.Format("The context type '{0}' does not contain member '{1}' which is specified in dbml", model.ContextType, t.Member));
\r
619 member_type = table_member.GetMemberType();
\r
620 if (member_type.GetGenericTypeDefinition() != typeof(Table<>))
\r
621 throw new ArgumentException(String.Format("The table member type was unexpected: '{0}'", member_type));
\r
622 var rt = member_type.GetGenericArguments()[0];
\r
623 row_type = model.GetMetaType(rt);
\r
624 if (row_type == null)
\r
625 throw new ArgumentException(String.Format("MetaType for '{0}' was not found", rt));
\r
627 static IEnumerable<MemberInfo> GetFieldsAndProperties(Type type)
\r
629 foreach (var f in type.GetFields())
\r
631 foreach (var p in type.GetProperties())
\r
635 XmlMetaModel model;
\r
637 MemberInfo table_member;
\r
642 public override MethodInfo DeleteMethod
\r
644 get { throw new NotImplementedException(); }
\r
647 public override MethodInfo InsertMethod
\r
649 get { throw new NotImplementedException(); }
\r
651 public override MetaModel Model { get { return model; } }
\r
652 public override MetaType RowType { get { return row_type; } }
\r
653 Type MemberType { get { return member_type; } }
\r
654 public override string TableName { get { return t.Name; } }
\r
656 public override MethodInfo UpdateMethod
\r
658 get { throw new NotImplementedException(); }
\r
662 MethodInfo GetMethod(TableFunction f)
\r
666 foreach (var mf in model.GetFunctions())
\r
667 if (mf.Name == f.FunctionId)
\r
673 class XmlMetaType : MetaType
\r
675 XmlMetaModel model;
\r
677 ReadOnlyCollection<MetaAssociation> associations;
\r
679 ReadOnlyCollection<MetaDataMember> members, identity_members, persistent_members;
\r
681 public XmlMetaType(XmlMetaModel model, DbmlType type)
\r
683 this.model = model;
\r
685 runtime_type = model.GetTypeFromName(t.Name);
\r
687 var l = new List<MetaDataMember>();
\r
688 l.AddRange(Array.ConvertAll<DbmlColumn, MetaDataMember>(
\r
689 t.Columns.ToArray(), c => new XmlColumnMetaDataMember(model, this, c, i++)));
\r
690 members = new ReadOnlyCollection<MetaDataMember>(l);
\r
693 public override ReadOnlyCollection<MetaAssociation> Associations
\r
697 if (associations == null)
\r
699 var l = new List<MetaAssociation>();
\r
701 foreach (var a in t.Associations)
\r
702 l.Add(new XmlMetaAssociation(this, new XmlAssociationMetaDataMember(model, this, a, -1), a));
\r
703 associations = new ReadOnlyCollection<MetaAssociation>(l.ToArray());
\r
705 return associations;
\r
708 public override bool CanInstantiate { get { return !runtime_type.IsAbstract; } }
\r
709 public override ReadOnlyCollection<MetaDataMember> DataMembers { get { return members; } }
\r
710 public override MetaDataMember DBGeneratedIdentityMember
\r
712 get { return members.First(m => m.IsDbGenerated && m.IsPrimaryKey); }
\r
715 public override ReadOnlyCollection<MetaType> DerivedTypes
\r
717 get { throw new NotImplementedException(); }
\r
719 public override MetaDataMember Discriminator
\r
721 get { return members.First(m => m.IsDiscriminator); }
\r
723 public override bool HasAnyLoadMethod
\r
725 get { return members.Any(m => m.LoadMethod != null); }
\r
728 public override bool HasAnyValidateMethod
\r
730 get { throw new NotImplementedException(); }
\r
733 public override bool HasInheritance
\r
735 get { throw new NotImplementedException(); }
\r
737 public override bool HasInheritanceCode
\r
739 get { return t.InheritanceCode != null; }
\r
741 public override bool HasUpdateCheck { get { return members.Any(m => m.UpdateCheck != UpdateCheck.Never); } }
\r
742 public override ReadOnlyCollection<MetaDataMember> IdentityMembers
\r
746 if (identity_members == null)
\r
748 identity_members = new ReadOnlyCollection<MetaDataMember>(
\r
749 members.TakeWhile(m => m.IsPrimaryKey).ToArray());
\r
751 return identity_members;
\r
755 public override MetaType InheritanceBase
\r
757 get { throw new NotImplementedException(); }
\r
759 public override Object InheritanceCode { get { return t.InheritanceCode; } }
\r
761 public override MetaType InheritanceDefault
\r
763 get { throw new NotImplementedException(); }
\r
766 public override MetaType InheritanceRoot
\r
768 get { throw new NotImplementedException(); }
\r
771 public override ReadOnlyCollection<MetaType> InheritanceTypes
\r
773 get { throw new NotImplementedException(); }
\r
776 public override bool IsEntity { get { return true; } }
\r
777 public override bool IsInheritanceDefault { get { return t.IsInheritanceDefault; } }
\r
778 public override MetaModel Model { get { return model; } }
\r
779 public override string Name { get { return t.Name; } }
\r
781 public override MethodInfo OnLoadedMethod
\r
783 get { throw new NotImplementedException(); }
\r
786 public override MethodInfo OnValidateMethod
\r
788 get { throw new NotImplementedException(); }
\r
790 public override ReadOnlyCollection<MetaDataMember> PersistentDataMembers
\r
794 if (persistent_members == null)
\r
796 persistent_members = new ReadOnlyCollection<MetaDataMember>(
\r
797 members.TakeWhile(m => m.IsPersistent).ToArray());
\r
799 return persistent_members;
\r
802 public override MetaTable Table { get { return model.GetTable(runtime_type); } }
\r
803 public override Type Type { get { return runtime_type; } }
\r
804 public override MetaDataMember VersionMember { get { return members.First(m => m.IsVersion); } }
\r
806 public override MetaDataMember GetDataMember(MemberInfo member)
\r
808 //return members.First(m => m.Member == member);
\r
809 foreach (var m in members) if (m.Member == member) return m;
\r
810 throw new ArgumentException(String.Format("No corresponding metadata member for '{0}'", member));
\r
813 public override MetaType GetInheritanceType(Type type)
\r
815 return InheritanceTypes.First(t => t.Type == type);
\r
819 public override MetaType GetTypeForInheritanceCode(object code)
\r
821 throw new NotImplementedException();
\r
825 class XmlMetaAssociation : MetaAssociation
\r
827 //XmlMetaType owner;
\r
829 ReadOnlyCollection<MetaDataMember> these_keys, other_keys;
\r
830 MetaDataMember member;
\r
832 public XmlMetaAssociation(XmlMetaType owner, XmlMetaDataMember member, DbmlAssociation a)
\r
834 //this.owner = owner;
\r
835 this.member = member;
\r
837 SetupRelationship();
\r
841 /// This function sets up the relationship information based on the attribute <see cref="XmlMetaModel"/>.
\r
843 private void SetupRelationship()
\r
845 //Get the association target type
\r
846 Type targetType = member.Member.GetFirstInnerReturnType();
\r
848 var metaModel = ThisMember.DeclaringType.Model as XmlMetaModel;
\r
849 if (metaModel == null)
\r
851 throw new InvalidOperationException("Internal Error: MetaModel is not a XmlMetaModel");
\r
854 MetaTable otherTable = metaModel.GetTable(targetType);
\r
857 these_keys = GetKeys(a.ThisKey ?? String.Empty, ThisMember.DeclaringType);
\r
860 other_keys = GetKeys(a.OtherKey ?? String.Empty, otherTable.RowType);
\r
863 //Seperator used for key lists
\r
864 private static readonly char[] STRING_SEPERATOR = new[] { ',' };
\r
867 /// Returns a list of keys from the given meta type based on the key list string.
\r
869 /// <param name="keyListString">The key list string.</param>
\r
870 /// <param name="parentType">Type of the parent.</param>
\r
871 /// <returns></returns>
\r
872 private static ReadOnlyCollection<MetaDataMember> GetKeys(string keyListString, MetaType parentType)
\r
874 if (keyListString != null)
\r
876 var thisKeyList = new List<MetaDataMember>();
\r
878 string[] keyNames = keyListString.Split(STRING_SEPERATOR, StringSplitOptions.RemoveEmptyEntries);
\r
880 foreach (string rawKeyName in keyNames)
\r
882 string keyName = rawKeyName.Trim();
\r
884 //TODO: maybe speed the lookup up
\r
885 MetaDataMember key = (from dataMember in parentType.PersistentDataMembers
\r
886 where dataMember.Name == keyName
\r
887 select dataMember).SingleOrDefault();
\r
891 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
892 keyName, keyListString, parentType.Type.Name);
\r
894 throw new InvalidOperationException(errorMessage);
\r
897 thisKeyList.Add(key);
\r
900 return new ReadOnlyCollection<MetaDataMember>(thisKeyList);
\r
902 else //Key is the primary key of this table
\r
904 return parentType.IdentityMembers;
\r
908 public override bool DeleteOnNull { get { return a.DeleteOnNull; } }
\r
909 public override string DeleteRule { get { return a.DeleteRule; } }
\r
910 public override bool IsForeignKey { get { return a.IsForeignKey; } }
\r
912 public override bool IsMany
\r
914 get { throw new NotImplementedException(); }
\r
916 public override bool IsNullable { get { return member.Member.GetMemberType().IsNullable(); } }
\r
917 public override bool IsUnique { get { return a.IsUnique; } }
\r
918 public override ReadOnlyCollection<MetaDataMember> OtherKey { get { return other_keys; } }
\r
919 public override bool OtherKeyIsPrimaryKey { get { return OtherKey.All(m => m.IsPrimaryKey); } }
\r
921 public override MetaDataMember OtherMember
\r
923 get { throw new NotImplementedException(); }
\r
925 public override MetaType OtherType { get { return OtherMember.DeclaringType; } }
\r
926 public override ReadOnlyCollection<MetaDataMember> ThisKey { get { return these_keys; } }
\r
927 public override bool ThisKeyIsPrimaryKey { get { return ThisKey.All(m => m.IsPrimaryKey); } }
\r
928 public override MetaDataMember ThisMember { get { return member; } }
\r
931 abstract class XmlMetaDataMember : MetaDataMember
\r
933 internal XmlMetaModel model;
\r
934 internal XmlMetaType type;
\r
935 internal MemberInfo member, storage;
\r
936 MetaAccessor member_accessor, storage_accessor;
\r
939 protected XmlMetaDataMember(XmlMetaModel model, XmlMetaType type, string memberName, string storageName, int ordinal)
\r
941 this.model = model;
\r
943 BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
\r
944 if (type.Type.GetMember(memberName, bf).Length == 0)
\r
945 throw new ArgumentException(String.Format("Specified member '{0}' was not found in type '{1}'", memberName, type.Name));
\r
946 if (type.Type.GetMember(storageName, bf).Length == 0)
\r
947 throw new ArgumentException(String.Format("Specified member '{0}' was not found in type '{1}'", storageName, type.Name));
\r
948 this.member = type.Type.GetMember(memberName, bf)[0];
\r
949 this.storage = type.Type.GetMember(storageName, bf)[0];
\r
950 this.ordinal = ordinal;
\r
953 public override bool CanBeNull { get { return member.GetMemberType().IsNullable(); } }
\r
954 public override MetaType DeclaringType { get { return type; } }
\r
955 public override bool IsDeferred { get { return false; } }
\r
956 public override bool IsPersistent { get { return true; } }
\r
957 public override MemberInfo Member { get { return member; } }
\r
958 public override MetaAccessor MemberAccessor
\r
962 if (member_accessor == null)
\r
963 member_accessor = new XmlMetaAccessor(this, Member);
\r
964 return member_accessor;
\r
967 public override int Ordinal { get { return ordinal; } }
\r
968 public override MetaAccessor StorageAccessor
\r
972 if (storage_accessor == null)
\r
973 storage_accessor = new XmlMetaAccessor(this, StorageMember);
\r
974 return storage_accessor;
\r
977 public override MemberInfo StorageMember { get { return storage; } }
\r
978 public override Type Type { get { return member.GetMemberType(); } }
\r
980 public override bool IsDeclaredBy(MetaType type)
\r
982 return this.type == type;
\r
986 class XmlColumnMetaDataMember : XmlMetaDataMember
\r
990 public XmlColumnMetaDataMember(XmlMetaModel model, XmlMetaType type, DbmlColumn column, int ordinal)
\r
991 : base(model, type, column.Member, column.Storage, ordinal)
\r
996 public override MetaAssociation Association { get { return null; } }
\r
997 public override AutoSync AutoSync { get { return (AutoSync)c.AutoSync; } }
\r
998 public override string DbType { get { return c.DbType; } }
\r
1000 public override MetaAccessor DeferredSourceAccessor
\r
1002 get { throw new NotImplementedException(); }
\r
1005 public override MetaAccessor DeferredValueAccessor
\r
1007 get { throw new NotImplementedException(); }
\r
1010 public override string Expression { get { return c.Expression; } }
\r
1011 public override bool IsAssociation { get { return false; } }
\r
1012 public override bool IsDbGenerated { get { return c.IsDbGenerated; } }
\r
1013 public override bool IsDiscriminator { get { return c.IsDiscriminator; } }
\r
1014 public override bool IsPrimaryKey { get { return c.IsPrimaryKey; } }
\r
1015 public override bool IsVersion { get { return c.IsVersion; } }
\r
1017 public override MethodInfo LoadMethod
\r
1021 throw new NotImplementedException();
\r
1024 public override string MappedName { get { return c.Name; } }
\r
1025 public override string Name { get { return c.Name ?? c.Member; } }
\r
1026 public override UpdateCheck UpdateCheck { get { return c.UpdateCheck; } }
\r
1029 class XmlAssociationMetaDataMember : XmlMetaDataMember
\r
1031 DbmlAssociation a;
\r
1032 XmlMetaAssociation ma;
\r
1034 public XmlAssociationMetaDataMember(XmlMetaModel model, XmlMetaType type, DbmlAssociation association, int ordinal)
\r
1035 : base(model, type, association.Member, association.Storage, ordinal)
\r
1037 this.a = association;
\r
1040 public override MetaAssociation Association
\r
1045 this.ma = new XmlMetaAssociation(type, this, a);
\r
1049 public override AutoSync AutoSync { get { return AutoSync.Never; } }
\r
1050 public override string DbType { get { return String.Empty; } }
\r
1052 public override MetaAccessor DeferredSourceAccessor
\r
1054 get { throw new NotImplementedException(); }
\r
1057 public override MetaAccessor DeferredValueAccessor
\r
1059 get { throw new NotImplementedException(); }
\r
1062 public override string Expression { get { return String.Empty; } }
\r
1063 public override bool IsAssociation { get { return true; } }
\r
1064 public override bool IsDbGenerated { get { return false; } }
\r
1065 public override bool IsDiscriminator { get { return false; } }
\r
1067 public override bool IsPrimaryKey
\r
1069 get { throw new NotImplementedException(); }
\r
1072 public override bool IsVersion
\r
1074 get { throw new NotImplementedException(); }
\r
1077 public override MethodInfo LoadMethod
\r
1081 throw new NotImplementedException();
\r
1084 public override string MappedName { get { return a.Member; } }
\r
1085 public override string Name { get { return a.Name; } }
\r
1086 public override UpdateCheck UpdateCheck
\r
1090 throw new NotImplementedException();
\r
1095 class XmlMetaAccessor : MetaAccessor
\r
1097 XmlMetaDataMember member;
\r
1098 MemberInfo member_info;
\r
1100 public XmlMetaAccessor(XmlMetaDataMember member, MemberInfo memberInfo)
\r
1102 this.member = member;
\r
1103 this.member_info = memberInfo;
\r
1106 public override Type Type
\r
1108 get { return member_info is FieldInfo ? ((FieldInfo)member_info).FieldType : ((PropertyInfo)member_info).PropertyType; }
\r
1112 public override object GetBoxedValue(object instance)
\r
1114 throw new NotImplementedException();
\r
1118 public override void SetBoxedValue(ref object instance, object value)
\r
1120 throw new NotImplementedException();
\r
1124 class XmlMetaFunction : MetaFunction
\r
1126 XmlMetaModel model;
\r
1128 MethodInfo method;
\r
1129 ReadOnlyCollection<MetaParameter> parameters;
\r
1130 ReadOnlyCollection<MetaType> result_types;
\r
1131 MetaParameter return_param;
\r
1133 public XmlMetaFunction(XmlMetaModel model, DbmlFunction function)
\r
1135 this.model = model;
\r
1136 this.f = function;
\r
1137 method = model.ContextType.GetMethod(function.Method);
\r
1138 return_param = new XmlMetaParameter(function.Return.DbType, String.Empty, method.ReturnParameter);
\r
1141 public override bool HasMultipleResults { get { return f.ElementTypes.Count > 0; } }
\r
1142 public override bool IsComposable { get { return f.IsComposable; } }
\r
1143 public override string MappedName { get { return f.Name; } }
\r
1144 public override MethodInfo Method { get { return method; } }
\r
1145 public override MetaModel Model { get { return model; } }
\r
1146 public override string Name { get { return f.Name; } }
\r
1147 public override ReadOnlyCollection<MetaParameter> Parameters
\r
1151 if (parameters == null)
\r
1153 var l = new List<MetaParameter>();
\r
1155 ParameterInfo[] mparams = method.GetParameters();
\r
1156 foreach (var p in f.Parameters)
\r
1157 l.Add(new XmlMetaParameter(p, mparams[i++]));
\r
1158 parameters = new ReadOnlyCollection<MetaParameter>(l);
\r
1160 return parameters;
\r
1163 public override ReadOnlyCollection<MetaType> ResultRowTypes
\r
1167 if (result_types == null)
\r
1169 var l = new List<MetaType>();
\r
1170 foreach (var p in f.ElementTypes)
\r
1171 l.Add(model.GetMetaType(model.GetTypeFromName(p.Name)));
\r
1172 result_types = new ReadOnlyCollection<MetaType>(l.ToArray());
\r
1174 return result_types;
\r
1177 public override MetaParameter ReturnParameter { get { return return_param; } }
\r