| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Linq.Expressions;
- using System.Reflection;
- using System.Text;
- using System.Linq;
- using System.Data.Linq.Provider;
- using System.Data.Linq.SqlClient;
- using System.Threading;
- using LinqToSqlShared.Mapping;
- using System.Runtime.CompilerServices;
- namespace System.Data.Linq.Mapping {
- internal static class MethodFinder {
- internal static MethodInfo FindMethod(Type type, string name, BindingFlags flags, Type[] argTypes) {
- return FindMethod(type, name, flags, argTypes, true);
- }
- internal static MethodInfo FindMethod(Type type, string name, BindingFlags flags, Type[] argTypes, bool allowInherit) {
- for (; type != typeof(object); type = type.BaseType) {
- MethodInfo mi = type.GetMethod(name, flags | BindingFlags.DeclaredOnly, null, argTypes, null);
- if (mi != null || !allowInherit) {
- return mi;
- }
- }
- return null;
- }
- }
- internal static class InheritanceBaseFinder {
- internal static MetaType FindBase(MetaType derivedType) {
- if (derivedType.Type == typeof(object)) {
- return null;
- }
- var clrType = derivedType.Type; // start
- var rootClrType = derivedType.InheritanceRoot.Type; // end
- var metaTable = derivedType.Table;
- MetaType metaType = null;
- while (true) {
- if (clrType == typeof(object) || clrType == rootClrType) {
- return null;
- }
- clrType = clrType.BaseType;
- metaType = derivedType.InheritanceRoot.GetInheritanceType(clrType);
- if (metaType != null) {
- return metaType;
- }
- }
- }
- }
- internal class AttributedMetaModel : MetaModel {
- ReaderWriterLock @lock = new ReaderWriterLock();
- MappingSource mappingSource;
- Type contextType;
- Type providerType;
- Dictionary<Type, MetaType> metaTypes;
- Dictionary<Type, MetaTable> metaTables;
- ReadOnlyCollection<MetaTable> staticTables;
- Dictionary<MetaPosition, MetaFunction> metaFunctions;
- string dbName;
- bool initStaticTables;
- bool initFunctions;
- internal AttributedMetaModel(MappingSource mappingSource, Type contextType) {
- this.mappingSource = mappingSource;
- this.contextType = contextType;
- this.metaTypes = new Dictionary<Type, MetaType>();
- this.metaTables = new Dictionary<Type, MetaTable>();
- this.metaFunctions = new Dictionary<MetaPosition, MetaFunction>();
- // Provider type
- ProviderAttribute[] attrs = (ProviderAttribute[])this.contextType.GetCustomAttributes(typeof(ProviderAttribute), true);
- if (attrs != null && attrs.Length == 1) { // Provider attribute is !AllowMultiple
- this.providerType = attrs[0].Type;
- } else {
- this.providerType = typeof(SqlProvider);
- }
- // Database name
- DatabaseAttribute[] das = (DatabaseAttribute[])this.contextType.GetCustomAttributes(typeof(DatabaseAttribute), false);
- this.dbName = (das != null && das.Length > 0) ? das[0].Name : this.contextType.Name;
- }
- public override MappingSource MappingSource {
- get { return this.mappingSource; }
- }
- public override Type ContextType {
- get { return this.contextType; }
- }
- public override string DatabaseName {
- get { return this.dbName; }
- }
- public override Type ProviderType {
- get { return this.providerType; }
- }
- public override IEnumerable<MetaTable> GetTables() {
- this.InitStaticTables();
- if (this.staticTables.Count > 0) {
- return this.staticTables;
- }
- else {
- @lock.AcquireReaderLock(Timeout.Infinite);
- try {
- return this.metaTables.Values.Where(x => x != null).Distinct();
- }
- finally {
- @lock.ReleaseReaderLock();
- }
- }
- }
- #region Initialization
- private void InitStaticTables() {
- if (!this.initStaticTables) {
- @lock.AcquireWriterLock(Timeout.Infinite);
- try {
- if (!this.initStaticTables) {
- HashSet<MetaTable> tables = new HashSet<MetaTable>();
- for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) {
- FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
- foreach (FieldInfo fi in fields) {
- Type ft = fi.FieldType;
- if (ft.IsGenericType && ft.GetGenericTypeDefinition() == typeof(Table<>)) {
- Type rowType = ft.GetGenericArguments()[0];
- tables.Add(this.GetTableNoLocks(rowType));
- }
- }
- PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
- foreach (PropertyInfo pi in props) {
- Type pt = pi.PropertyType;
- if (pt.IsGenericType && pt.GetGenericTypeDefinition() == typeof(Table<>)) {
- Type rowType = pt.GetGenericArguments()[0];
- tables.Add(this.GetTableNoLocks(rowType));
- }
- }
- }
- this.staticTables = new List<MetaTable>(tables).AsReadOnly();
- this.initStaticTables = true;
- }
- }
- finally {
- @lock.ReleaseWriterLock();
- }
- }
- }
- private void InitFunctions() {
- if (!this.initFunctions) {
- @lock.AcquireWriterLock(Timeout.Infinite);
- try {
- if (!this.initFunctions) {
- if (this.contextType != typeof(DataContext)) {
- for (Type type = this.contextType; type != typeof(DataContext); type = type.BaseType) {
- foreach (MethodInfo mi in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) {
- if (IsUserFunction(mi)) {
- if (mi.IsGenericMethodDefinition) {
- // Added this constraint because XML mapping model didn't support mapping sprocs to generic method.
- // The attribute mapping model was, however, able to support it. This check is for parity between
- // the two models.
- throw Error.InvalidUseOfGenericMethodAsMappedFunction(mi.Name);
- }
- MetaPosition mp = new MetaPosition(mi);
- if (!this.metaFunctions.ContainsKey(mp)) {
- MetaFunction metaFunction = new AttributedMetaFunction(this, mi);
- this.metaFunctions.Add(mp, metaFunction);
- // pre-set all known function result types into metaType map
- foreach (MetaType rt in metaFunction.ResultRowTypes) {
- foreach (MetaType it in rt.InheritanceTypes) {
- if (!this.metaTypes.ContainsKey(it.Type)) {
- this.metaTypes.Add(it.Type, it);
- }
- }
- }
- }
- }
- }
- }
- }
- this.initFunctions = true;
- }
- }
- finally {
- @lock.ReleaseWriterLock();
- }
- }
- }
- private static bool IsUserFunction(MethodInfo mi) {
- return Attribute.GetCustomAttribute(mi, typeof(FunctionAttribute), false) != null;
- }
- #endregion
- public override MetaTable GetTable(Type rowType) {
- if (rowType == null) {
- throw Error.ArgumentNull("rowType");
- }
- MetaTable table;
- @lock.AcquireReaderLock(Timeout.Infinite);
- try {
- if (this.metaTables.TryGetValue(rowType, out table)) {
- return table;
- }
- }
- finally {
- @lock.ReleaseReaderLock();
- }
- @lock.AcquireWriterLock(Timeout.Infinite);
- try {
- table = this.GetTableNoLocks(rowType);
- }
- finally {
- @lock.ReleaseWriterLock();
- }
- return table;
- }
- internal MetaTable GetTableNoLocks(Type rowType) {
- MetaTable table;
- if (!this.metaTables.TryGetValue(rowType, out table)) {
- Type root = GetRoot(rowType) ?? rowType;
- TableAttribute[] attrs = (TableAttribute[])root.GetCustomAttributes(typeof(TableAttribute), true);
- if (attrs.Length == 0) {
- this.metaTables.Add(rowType, null);
- }
- else {
- if (!this.metaTables.TryGetValue(root, out table)) {
- table = new AttributedMetaTable(this, attrs[0], root);
- foreach (MetaType mt in table.RowType.InheritanceTypes) {
- this.metaTables.Add(mt.Type, table);
- }
- }
- // catch case of derived type that is not part of inheritance
- if (table.RowType.GetInheritanceType(rowType) == null) {
- this.metaTables.Add(rowType, null);
- return null;
- }
- }
- }
- return table;
- }
- private static Type GetRoot(Type derivedType) {
- while (derivedType != null && derivedType != typeof(object)) {
- TableAttribute[] attrs = (TableAttribute[])derivedType.GetCustomAttributes(typeof(TableAttribute), false);
- if (attrs.Length > 0)
- return derivedType;
- derivedType = derivedType.BaseType;
- }
- return null;
- }
- public override MetaType GetMetaType(Type type) {
- if (type == null) {
- throw Error.ArgumentNull("type");
- }
- MetaType mtype = null;
- @lock.AcquireReaderLock(Timeout.Infinite);
- try {
- if (this.metaTypes.TryGetValue(type, out mtype)) {
- return mtype;
- }
- }
- finally {
- @lock.ReleaseReaderLock();
- }
- // Attributed meta model allows us to learn about tables we did not
- // statically know about
- MetaTable tab = this.GetTable(type);
- if (tab != null) {
- return tab.RowType.GetInheritanceType(type);
- }
- this.InitFunctions();
- @lock.AcquireWriterLock(Timeout.Infinite);
- try {
- if (!this.metaTypes.TryGetValue(type, out mtype)) {
- mtype = new UnmappedType(this, type);
- this.metaTypes.Add(type, mtype);
- }
- }
- finally {
- @lock.ReleaseWriterLock();
- }
- return mtype;
- }
- public override MetaFunction GetFunction(MethodInfo method) {
- if (method == null) {
- throw Error.ArgumentNull("method");
- }
- this.InitFunctions();
- MetaFunction function = null;
- this.metaFunctions.TryGetValue(new MetaPosition(method), out function);
- return function;
- }
- public override IEnumerable<MetaFunction> GetFunctions() {
- this.InitFunctions();
- return this.metaFunctions.Values.ToList().AsReadOnly();
- }
- }
- internal sealed class AttributedMetaTable : MetaTable {
- AttributedMetaModel model;
- string tableName;
- MetaType rowType;
- bool hasMethods;
- MethodInfo insertMethod;
- MethodInfo updateMethod;
- MethodInfo deleteMethod;
- internal AttributedMetaTable(AttributedMetaModel model, TableAttribute attr, Type rowType) {
- this.model = model;
- this.tableName = string.IsNullOrEmpty(attr.Name) ? rowType.Name : attr.Name;
- this.rowType = new AttributedRootType(model, this, rowType);
- }
- public override MetaModel Model {
- get { return this.model; }
- }
- public override string TableName {
- get { return this.tableName; }
- }
- public override MetaType RowType {
- get { return this.rowType; }
- }
- public override MethodInfo InsertMethod {
- get {
- this.InitMethods();
- return this.insertMethod;
- }
- }
- public override MethodInfo UpdateMethod {
- get {
- this.InitMethods();
- return this.updateMethod;
- }
- }
- public override MethodInfo DeleteMethod {
- get {
- this.InitMethods();
- return this.deleteMethod;
- }
- }
- private void InitMethods() {
- if (!this.hasMethods) {
- this.insertMethod = MethodFinder.FindMethod(
- this.model.ContextType,
- "Insert" + rowType.Name,
- BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
- new Type[] { rowType.Type }
- );
- this.updateMethod = MethodFinder.FindMethod(
- this.model.ContextType,
- "Update" + rowType.Name,
- BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
- new Type[] { rowType.Type }
- );
- this.deleteMethod = MethodFinder.FindMethod(
- this.model.ContextType,
- "Delete" + rowType.Name,
- BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
- new Type[] { rowType.Type }
- );
- this.hasMethods = true;
- }
- }
- }
- internal sealed class AttributedRootType : AttributedMetaType {
- Dictionary<Type, MetaType> types;
- Dictionary<object, MetaType> codeMap;
- ReadOnlyCollection<MetaType> inheritanceTypes;
- MetaType inheritanceDefault;
- internal AttributedRootType(AttributedMetaModel model, AttributedMetaTable table, Type type)
- : base(model, table, type, null) {
- // check for inheritance and create all other types
- InheritanceMappingAttribute[] inheritanceInfo = (InheritanceMappingAttribute[])type.GetCustomAttributes(typeof(InheritanceMappingAttribute), true);
- if (inheritanceInfo.Length > 0) {
- if (this.Discriminator == null) {
- throw Error.NoDiscriminatorFound(type);
- }
- if (!MappingSystem.IsSupportedDiscriminatorType(this.Discriminator.Type)) {
- throw Error.DiscriminatorClrTypeNotSupported(this.Discriminator.DeclaringType.Name, this.Discriminator.Name, this.Discriminator.Type);
- }
- this.types = new Dictionary<Type, MetaType>();
- this.types.Add(type, this); // add self
- this.codeMap = new Dictionary<object, MetaType>();
- // initialize inheritance types
- foreach (InheritanceMappingAttribute attr in inheritanceInfo) {
- if (!type.IsAssignableFrom(attr.Type)) {
- throw Error.InheritanceTypeDoesNotDeriveFromRoot(attr.Type, type);
- }
- if (attr.Type.IsAbstract) {
- throw Error.AbstractClassAssignInheritanceDiscriminator(attr.Type);
- }
- AttributedMetaType mt = this.CreateInheritedType(type, attr.Type);
- if (attr.Code == null) {
- throw Error.InheritanceCodeMayNotBeNull();
- }
- if (mt.inheritanceCode != null) {
- throw Error.InheritanceTypeHasMultipleDiscriminators(attr.Type);
- }
- object codeValue = DBConvert.ChangeType(attr.Code, this.Discriminator.Type);
- foreach (object d in codeMap.Keys) {
- // if the keys are equal, or if they are both strings containing only spaces
- // they are considered equal
- if ((codeValue.GetType() == typeof(string) && ((string)codeValue).Trim().Length == 0 &&
- d.GetType() == typeof(string) && ((string)d).Trim().Length == 0) ||
- object.Equals(d, codeValue)) {
- throw Error.InheritanceCodeUsedForMultipleTypes(codeValue);
- }
- }
- mt.inheritanceCode = codeValue;
- this.codeMap.Add(codeValue, mt);
- if (attr.IsDefault) {
- if (this.inheritanceDefault != null) {
- throw Error.InheritanceTypeHasMultipleDefaults(type);
- }
- this.inheritanceDefault = mt;
- }
- }
- if (this.inheritanceDefault == null) {
- throw Error.InheritanceHierarchyDoesNotDefineDefault(type);
- }
- }
- if (this.types != null) {
- this.inheritanceTypes = this.types.Values.ToList().AsReadOnly();
- }
- else {
- this.inheritanceTypes = new MetaType[] { this }.ToList().AsReadOnly();
- }
- this.Validate();
- }
- private void Validate() {
- Dictionary<object, string> memberToColumn = new Dictionary<object, string>();
- foreach (MetaType type in this.InheritanceTypes) {
- if (type != this) {
- TableAttribute[] attrs = (TableAttribute[])type.Type.GetCustomAttributes(typeof(TableAttribute), false);
- if (attrs.Length > 0)
- throw Error.InheritanceSubTypeIsAlsoRoot(type.Type);
- }
- foreach (MetaDataMember mem in type.PersistentDataMembers) {
- if (mem.IsDeclaredBy(type)) {
- if (mem.IsDiscriminator && !this.HasInheritance) {
- throw Error.NonInheritanceClassHasDiscriminator(type);
- }
- if (!mem.IsAssociation) {
- // validate that no database column is mapped twice
- if (!string.IsNullOrEmpty(mem.MappedName)) {
- string column;
- object dn = InheritanceRules.DistinguishedMemberName(mem.Member);
- if (memberToColumn.TryGetValue(dn, out column)) {
- if (column != mem.MappedName) {
- throw Error.MemberMappedMoreThanOnce(mem.Member.Name);
- }
- }
- else {
- memberToColumn.Add(dn, mem.MappedName);
- }
- }
- }
- }
- }
- }
- }
- public override bool HasInheritance {
- get { return this.types != null; }
- }
-
- private AttributedMetaType CreateInheritedType(Type root, Type type) {
- MetaType metaType;
- if (!this.types.TryGetValue(type, out metaType)) {
- metaType = new AttributedMetaType(this.Model, this.Table, type, this);
- this.types.Add(type, metaType);
- if (type != root && type.BaseType != typeof(object)) {
- this.CreateInheritedType(root, type.BaseType);
- }
- }
- return (AttributedMetaType)metaType;
- }
- public override ReadOnlyCollection<MetaType> InheritanceTypes {
- get { return this.inheritanceTypes; }
- }
- public override MetaType GetInheritanceType(Type type) {
- if (type == this.Type)
- return this;
- MetaType metaType = null;
- if (this.types != null) {
- this.types.TryGetValue(type, out metaType);
- }
- return metaType;
- }
- public override MetaType InheritanceDefault {
- get { return this.inheritanceDefault; }
- }
- }
- internal class AttributedMetaType : MetaType {
- MetaModel model;
- MetaTable table;
- Type type;
- Dictionary<MetaPosition, MetaDataMember> dataMemberMap;
- ReadOnlyCollection<MetaDataMember> dataMembers;
- ReadOnlyCollection<MetaDataMember> persistentMembers;
- ReadOnlyCollection<MetaDataMember> identities;
- MetaDataMember dbGeneratedIdentity;
- MetaDataMember version;
- MetaDataMember discriminator;
- MetaType inheritanceRoot;
- bool inheritanceBaseSet;
- MetaType inheritanceBase;
- internal object inheritanceCode;
- ReadOnlyCollection<MetaType> derivedTypes;
- ReadOnlyCollection<MetaAssociation> associations;
- bool hasMethods;
- bool hasAnyLoadMethod;
- bool hasAnyValidateMethod;
- MethodInfo onLoadedMethod;
- MethodInfo onValidateMethod;
- object locktarget = new object(); // Hold locks on private object rather than public MetaType.
- internal AttributedMetaType(MetaModel model, MetaTable table, Type type, MetaType inheritanceRoot) {
- this.model = model;
- this.table = table;
- this.type = type;
- this.inheritanceRoot = (inheritanceRoot != null) ? inheritanceRoot : this;
- // Not lazy-loading to simplify locking and enhance performance
- // (because no lock will be required for the common read scenario).
- this.InitDataMembers();
- this.identities = this.dataMembers.Where(m => m.IsPrimaryKey).ToList().AsReadOnly();
- this.persistentMembers = this.dataMembers.Where(m => m.IsPersistent).ToList().AsReadOnly();
- }
- #region Initialization
- private void ValidatePrimaryKeyMember(MetaDataMember mm) {
- //if the type is a sub-type, no member declared in the type can be primary key
- if (mm.IsPrimaryKey && this.inheritanceRoot != this && mm.Member.DeclaringType == this.type) {
- throw(Error.PrimaryKeyInSubTypeNotSupported(this.type.Name, mm.Name));
- }
- }
- private void InitMethods() {
- if (!this.hasMethods) {
- this.onLoadedMethod = MethodFinder.FindMethod(
- this.Type,
- "OnLoaded",
- BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
- Type.EmptyTypes,
- false
- );
- this.onValidateMethod = MethodFinder.FindMethod(
- this.Type,
- "OnValidate",
- BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
- new[] { typeof(ChangeAction) },
- false
- );
- this.hasAnyLoadMethod = (this.onLoadedMethod != null) || (this.InheritanceBase != null && this.InheritanceBase.HasAnyLoadMethod);
- this.hasAnyValidateMethod = (this.onValidateMethod != null) || (this.InheritanceBase != null && this.InheritanceBase.HasAnyValidateMethod);
- this.hasMethods = true;
- }
- }
- private void InitDataMembers() {
- if (this.dataMembers == null) {
- this.dataMemberMap = new Dictionary<MetaPosition, MetaDataMember>();
- int ordinal = 0;
- BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
- FieldInfo[] fis = TypeSystem.GetAllFields(this.type, flags).ToArray();
- if (fis != null) {
- for (int i = 0, n = fis.Length; i < n; i++) {
- FieldInfo fi = fis[i];
- MetaDataMember mm = new AttributedMetaDataMember(this, fi, ordinal);
- ValidatePrimaryKeyMember(mm);
- // must be public or persistent
- if (!mm.IsPersistent && !fi.IsPublic)
- continue;
- this.dataMemberMap.Add(new MetaPosition(fi), mm);
- ordinal++;
- // must be persistent for the rest
- if (!mm.IsPersistent)
- continue;
- this.InitSpecialMember(mm);
- }
- }
-
- PropertyInfo[] pis = TypeSystem.GetAllProperties(this.type, flags).ToArray();
- if (pis != null) {
- for (int i = 0, n = pis.Length; i < n; i++) {
- PropertyInfo pi = pis[i];
- MetaDataMember mm = new AttributedMetaDataMember(this, pi, ordinal);
- ValidatePrimaryKeyMember(mm);
- // must be public or persistent
- bool isPublic = (pi.CanRead && pi.GetGetMethod(false) != null)
- && (!pi.CanWrite || pi.GetSetMethod(false) != null);
- if (!mm.IsPersistent && !isPublic)
- continue;
- this.dataMemberMap.Add(new MetaPosition(pi), mm);
- ordinal++;
- // must be persistent for the rest
- if (!mm.IsPersistent)
- continue;
- this.InitSpecialMember(mm);
- }
- }
- this.dataMembers = new List<MetaDataMember>(this.dataMemberMap.Values).AsReadOnly();
- }
- }
- private void InitSpecialMember(MetaDataMember mm) {
- // Can only have one auto gen member that is also an identity member,
- // except if that member is a computed column (since they are implicitly auto gen)
- if (mm.IsDbGenerated && mm.IsPrimaryKey && string.IsNullOrEmpty(mm.Expression)) {
- if (this.dbGeneratedIdentity != null)
- throw Error.TwoMembersMarkedAsPrimaryKeyAndDBGenerated(mm.Member, this.dbGeneratedIdentity.Member);
- this.dbGeneratedIdentity = mm;
- }
- if (mm.IsPrimaryKey && !MappingSystem.IsSupportedIdentityType(mm.Type))
- {
- throw Error.IdentityClrTypeNotSupported(mm.DeclaringType, mm.Name, mm.Type);
- }
- if (mm.IsVersion) {
- if (this.version != null)
- throw Error.TwoMembersMarkedAsRowVersion(mm.Member, this.version.Member);
- this.version = mm;
- }
- if (mm.IsDiscriminator) {
- if (this.discriminator!=null)
- throw Error.TwoMembersMarkedAsInheritanceDiscriminator(mm.Member, this.discriminator.Member);
- this.discriminator = mm;
- }
- }
- #endregion
- public override MetaModel Model {
- get { return this.model; }
- }
- public override MetaTable Table {
- get { return this.table; }
- }
- public override Type Type {
- get { return this.type; }
- }
- public override string Name {
- get { return this.type.Name; }
- }
- public override bool IsEntity {
- get {
- if (this.table != null) {
- return table.RowType.IdentityMembers.Count > 0;
- }
- return false;
- }
- }
- public override bool CanInstantiate {
- get { return !this.type.IsAbstract && (this == this.InheritanceRoot || this.HasInheritanceCode); }
- }
- public override MetaDataMember DBGeneratedIdentityMember {
- get { return this.dbGeneratedIdentity; }
- }
- public override MetaDataMember VersionMember {
- get { return this.version; }
- }
- public override MetaDataMember Discriminator {
- get { return this.discriminator; }
- }
- public override bool HasUpdateCheck {
- get {
- foreach(MetaDataMember member in this.PersistentDataMembers) {
- if (member.UpdateCheck != UpdateCheck.Never) {
- return true;
- }
- }
- return false;
- }
- }
- public override bool HasInheritance {
- get { return this.inheritanceRoot.HasInheritance; }
- }
- public override bool HasInheritanceCode {
- get { return this.inheritanceCode != null; }
- }
- public override object InheritanceCode {
- get { return this.inheritanceCode; }
- }
- public override MetaType InheritanceRoot {
- get { return this.inheritanceRoot; }
- }
- public override MetaType InheritanceBase {
- get {
- // LOCKING: Cannot initialize at construction
- if (!this.inheritanceBaseSet && this.inheritanceBase == null) {
- lock (this.locktarget) {
- if (this.inheritanceBase == null) {
- this.inheritanceBase = InheritanceBaseFinder.FindBase(this);
- this.inheritanceBaseSet = true;
- }
- }
- }
- return this.inheritanceBase;
- }
- }
- public override MetaType InheritanceDefault {
- get { return this.InheritanceRoot.InheritanceDefault; }
- }
- public override bool IsInheritanceDefault {
- get { return this.InheritanceDefault == this; }
- }
- public override ReadOnlyCollection<MetaType> InheritanceTypes {
- get { return this.inheritanceRoot.InheritanceTypes; }
- }
- public override MetaType GetInheritanceType(Type inheritanceType) {
- if (inheritanceType == this.type)
- return this;
- return this.inheritanceRoot.GetInheritanceType(inheritanceType);
- }
- public override ReadOnlyCollection<MetaType> DerivedTypes {
- get {
- // LOCKING: Cannot initialize at construction because derived types
- // won't exist yet.
- if (this.derivedTypes == null) {
- lock (this.locktarget) {
- if (this.derivedTypes == null) {
- List<MetaType> dTypes = new List<MetaType>();
- foreach (MetaType mt in this.InheritanceTypes) {
- if (mt.Type.BaseType == this.type)
- dTypes.Add(mt);
- }
- this.derivedTypes = dTypes.AsReadOnly();
- }
- }
- }
- return this.derivedTypes;
- }
- }
- public override MetaType GetTypeForInheritanceCode(object key) {
- if (this.InheritanceRoot.Discriminator.Type == typeof(string)) {
- string skey = (string)key;
- foreach (MetaType mt in this.InheritanceRoot.InheritanceTypes) {
- if (string.Compare((string)mt.InheritanceCode, skey, StringComparison.OrdinalIgnoreCase) == 0)
- return mt;
- }
- }
- else {
- foreach (MetaType mt in this.InheritanceRoot.InheritanceTypes) {
- if (object.Equals(mt.InheritanceCode, key))
- return mt;
- }
- }
- return null;
- }
- public override ReadOnlyCollection<MetaDataMember> DataMembers {
- get { return this.dataMembers; }
- }
- public override ReadOnlyCollection<MetaDataMember> PersistentDataMembers {
- get { return this.persistentMembers; }
- }
- public override ReadOnlyCollection<MetaDataMember> IdentityMembers {
- get { return this.identities; }
- }
- public override ReadOnlyCollection<MetaAssociation> Associations {
- get {
- // LOCKING: Associations are late-expanded so that cycles are broken.
- if (this.associations == null) {
- lock (this.locktarget) {
- if (this.associations == null) {
- this.associations = this.dataMembers.Where(m => m.IsAssociation).Select(m => m.Association).ToList().AsReadOnly();
- }
- }
- }
- return this.associations;
- }
- }
- public override MetaDataMember GetDataMember(MemberInfo mi) {
- if (mi == null)
- throw Error.ArgumentNull("mi");
- MetaDataMember mm = null;
- if (this.dataMemberMap.TryGetValue(new MetaPosition(mi), out mm)) {
- return mm;
- }
- else {
- // DON'T look to see if we are trying to get a member from an inherited type.
- // The calling code should know to look in the inherited type.
- if (mi.DeclaringType.IsInterface) {
- throw Error.MappingOfInterfacesMemberIsNotSupported(mi.DeclaringType.Name, mi.Name);
- } else { //the member is not mapped in the base class
- throw Error.UnmappedClassMember(mi.DeclaringType.Name, mi.Name);
- }
- }
- }
- public override MethodInfo OnLoadedMethod {
- get {
- this.InitMethods();
- return this.onLoadedMethod;
- }
- }
- public override MethodInfo OnValidateMethod {
- get {
- this.InitMethods();
- return this.onValidateMethod;
- }
- }
- public override bool HasAnyValidateMethod {
- get {
- this.InitMethods();
- return this.hasAnyValidateMethod;
- }
- }
- public override bool HasAnyLoadMethod {
- get {
- this.InitMethods();
- return this.hasAnyLoadMethod;
- }
- }
- public override string ToString() {
- return this.Name;
- }
- }
- internal sealed class AttributedMetaFunction : MetaFunction {
- private AttributedMetaModel model;
- private MethodInfo methodInfo;
- private FunctionAttribute functionAttrib;
- private MetaParameter returnParameter;
- private ReadOnlyCollection<MetaParameter> parameters;
- private ReadOnlyCollection<MetaType> rowTypes;
- static ReadOnlyCollection<MetaParameter> _emptyParameters = new List<MetaParameter>(0).AsReadOnly();
- static ReadOnlyCollection<MetaType> _emptyTypes = new List<MetaType>(0).AsReadOnly();
- /// <summary>
- /// Constructor.
- /// </summary>
- /// <param name="metaType">The parent meta type.</param>
- /// <param name="mi">The method info.</param>
- public AttributedMetaFunction(AttributedMetaModel model, MethodInfo mi) {
- this.model = model;
- this.methodInfo = mi;
- this.rowTypes = _emptyTypes;
- this.functionAttrib = Attribute.GetCustomAttribute(mi, typeof(FunctionAttribute), false) as FunctionAttribute;
- System.Diagnostics.Debug.Assert(functionAttrib != null);
- // Gather up all mapped results
- ResultTypeAttribute[] attrs = (ResultTypeAttribute[])Attribute.GetCustomAttributes(mi, typeof(ResultTypeAttribute));
- if (attrs.Length == 0 && mi.ReturnType == typeof(IMultipleResults)) {
- throw Error.NoResultTypesDeclaredForFunction(mi.Name);
- }
- else if (attrs.Length > 1 && mi.ReturnType != typeof(IMultipleResults)) {
- throw Error.TooManyResultTypesDeclaredForFunction(mi.Name);
- }
- else if (attrs.Length <= 1 && mi.ReturnType.IsGenericType &&
- (mi.ReturnType.GetGenericTypeDefinition() == typeof(IEnumerable<>) ||
- mi.ReturnType.GetGenericTypeDefinition() == typeof(ISingleResult<>) ||
- mi.ReturnType.GetGenericTypeDefinition() == typeof(IQueryable<>))) {
- Type elementType = TypeSystem.GetElementType(mi.ReturnType);
- this.rowTypes = new List<MetaType>(1) { this.GetMetaType(elementType) }.AsReadOnly();
- }
- else if (attrs.Length > 0) {
- List<MetaType> rowTypes = new List<MetaType>();
- foreach (ResultTypeAttribute rat in attrs) {
- Type type = rat.Type;
- MetaType mt = this.GetMetaType(type);
- // Only add unique meta types
- if (!rowTypes.Contains(mt)) {
- rowTypes.Add(mt);
- }
- }
- this.rowTypes = rowTypes.AsReadOnly();
- }
- else {
- this.returnParameter = new AttributedMetaParameter(this.methodInfo.ReturnParameter);
- }
- // gather up all meta parameter
- ParameterInfo[] pis = mi.GetParameters();
- if (pis.Length > 0) {
- List<MetaParameter> mps = new List<MetaParameter>(pis.Length);
- for (int i = 0, n = pis.Length; i < n; i++) {
- AttributedMetaParameter metaParam = new AttributedMetaParameter(pis[i]);
- mps.Add(metaParam);
- }
- this.parameters = mps.AsReadOnly();
- }
- else {
- this.parameters = _emptyParameters;
- }
- }
- /// <summary>
- /// For the specified type, if it is a mapped type, use the Table
- /// metatype to get the correct inheritance metatype,
- /// otherwise create a new meta type.
- /// </summary>
- private MetaType GetMetaType(Type type) {
- // call no-lock version of GetTable since this function is called only in constructor
- // and constructor is only called by function that already has a lock.
- MetaTable tbl = model.GetTableNoLocks(type);
- if (tbl != null) {
- return tbl.RowType.GetInheritanceType(type);
- }
- return new AttributedRootType(model, null, type);
- }
- public override MetaModel Model {
- get { return this.model; }
- }
- public override MethodInfo Method {
- get { return this.methodInfo; }
- }
- public override string Name {
- get { return this.methodInfo.Name; }
- }
- public override string MappedName {
- get {
- if (!string.IsNullOrEmpty(this.functionAttrib.Name)) {
- return this.functionAttrib.Name;
- }
- return this.methodInfo.Name;
- }
- }
- public override bool IsComposable {
- get { return this.functionAttrib.IsComposable; }
- }
- public override ReadOnlyCollection<MetaParameter> Parameters {
- get { return this.parameters; }
- }
- public override MetaParameter ReturnParameter {
- get { return this.returnParameter; }
- }
- public override bool HasMultipleResults {
- get { return this.methodInfo.ReturnType == typeof(IMultipleResults); }
- }
- public override ReadOnlyCollection<MetaType> ResultRowTypes {
- get { return this.rowTypes; }
- }
- }
- internal sealed class AttributedMetaParameter : MetaParameter {
- private ParameterInfo parameterInfo;
- private ParameterAttribute paramAttrib;
- public AttributedMetaParameter(ParameterInfo parameterInfo) {
- this.parameterInfo = parameterInfo;
- this.paramAttrib = Attribute.GetCustomAttribute(parameterInfo, typeof(ParameterAttribute), false) as ParameterAttribute;
- }
- public override ParameterInfo Parameter {
- get { return this.parameterInfo; }
- }
- public override string Name {
- get { return this.parameterInfo.Name; }
- }
- public override string MappedName {
- get {
- if (this.paramAttrib != null && this.paramAttrib.Name != null)
- return this.paramAttrib.Name;
- return this.parameterInfo.Name;
- }
- }
- public override Type ParameterType {
- get { return this.parameterInfo.ParameterType; }
- }
- public override string DbType {
- get {
- if (this.paramAttrib != null && this.paramAttrib.DbType != null)
- return this.paramAttrib.DbType;
- return null;
- }
- }
- }
- internal sealed class AttributedMetaDataMember : MetaDataMember {
- AttributedMetaType metaType;
- MemberInfo member;
- MemberInfo storageMember;
- int ordinal;
- Type type;
- Type declaringType;
- bool hasAccessors;
- MetaAccessor accPublic;
- MetaAccessor accPrivate;
- MetaAccessor accDefValue;
- MetaAccessor accDefSource;
- DataAttribute attr;
- ColumnAttribute attrColumn;
- AssociationAttribute attrAssoc;
- AttributedMetaAssociation assoc;
- bool isNullableType;
- bool isDeferred;
- object locktarget = new object(); // Hold locks on private object rather than public MetaType.
- bool hasLoadMethod;
- MethodInfo loadMethod;
-
- internal AttributedMetaDataMember(AttributedMetaType metaType, MemberInfo mi, int ordinal) {
- this.declaringType = mi.DeclaringType;
- this.metaType = metaType;
- this.member = mi;
- this.ordinal = ordinal;
- this.type = TypeSystem.GetMemberType(mi);
- this.isNullableType = TypeSystem.IsNullableType(this.type);
- this.attrColumn = (ColumnAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnAttribute));
- this.attrAssoc = (AssociationAttribute)Attribute.GetCustomAttribute(mi, typeof(AssociationAttribute));
- this.attr = (this.attrColumn != null) ? (DataAttribute)this.attrColumn : (DataAttribute)this.attrAssoc;
- if (this.attr != null && this.attr.Storage != null) {
- MemberInfo[] mis = mi.DeclaringType.GetMember(this.attr.Storage, BindingFlags.Instance | BindingFlags.NonPublic);
- if (mis == null || mis.Length != 1) {
- throw Error.BadStorageProperty(this.attr.Storage, mi.DeclaringType, mi.Name);
- }
- this.storageMember = mis[0];
- }
- Type storageType = this.storageMember != null ? TypeSystem.GetMemberType(this.storageMember) : this.type;
- this.isDeferred = IsDeferredType(storageType);
- if (attrColumn != null && attrColumn.IsDbGenerated && attrColumn.IsPrimaryKey) {
- // auto-gen identities must be synced on insert
- if ((attrColumn.AutoSync != AutoSync.Default) && (attrColumn.AutoSync != AutoSync.OnInsert)) {
- throw Error.IncorrectAutoSyncSpecification(mi.Name);
- }
- }
- }
- private void InitAccessors() {
- if (!this.hasAccessors) {
- lock (this.locktarget) {
- if (!this.hasAccessors) {
- if (this.storageMember != null) {
- this.accPrivate = MakeMemberAccessor(this.member.ReflectedType, this.storageMember, null);
- if (this.isDeferred) {
- MakeDeferredAccessors(this.member.ReflectedType, this.accPrivate, out this.accPrivate, out this.accDefValue, out this.accDefSource);
- }
- this.accPublic = MakeMemberAccessor(this.member.ReflectedType, this.member, this.accPrivate);
- }
- else {
- this.accPublic = this.accPrivate = MakeMemberAccessor(this.member.ReflectedType, this.member, null);
- if (this.isDeferred) {
- MakeDeferredAccessors(this.member.ReflectedType, this.accPrivate, out this.accPrivate, out this.accDefValue, out this.accDefSource);
- }
- }
- this.hasAccessors = true;
- }
- }
- }
- }
- public override MetaType DeclaringType {
- get { return this.metaType; }
- }
- public override bool IsDeclaredBy(MetaType declaringMetaType) {
- if (declaringMetaType == null) {
- throw Error.ArgumentNull("declaringMetaType");
- }
- return declaringMetaType.Type == this.declaringType;
- }
- public override MemberInfo Member {
- get { return this.member; }
- }
- public override MemberInfo StorageMember {
- get { return this.storageMember; }
- }
- public override string Name {
- get { return this.member.Name; }
- }
- public override int Ordinal {
- get { return this.ordinal; }
- }
- public override Type Type {
- get { return this.type; }
- }
- public override MetaAccessor MemberAccessor {
- get {
- this.InitAccessors();
- return this.accPublic;
- }
- }
- public override MetaAccessor StorageAccessor {
- get {
- this.InitAccessors();
- return this.accPrivate;
- }
- }
- public override MetaAccessor DeferredValueAccessor {
- get {
- this.InitAccessors();
- return this.accDefValue;
- }
- }
- public override MetaAccessor DeferredSourceAccessor {
- get {
- this.InitAccessors();
- return this.accDefSource;
- }
- }
- public override bool IsDeferred {
- get { return this.isDeferred; }
- }
- public override bool IsPersistent {
- get { return this.attrColumn != null || this.attrAssoc != null; }
- }
- public override bool IsAssociation {
- get { return this.attrAssoc != null; }
- }
- public override bool IsPrimaryKey {
- get { return this.attrColumn != null && this.attrColumn.IsPrimaryKey; }
- }
- /// <summary>
- /// Returns true if the member is explicitly marked as auto gen, or if the
- /// member is computed or generated by the database server.
- /// </summary>
- public override bool IsDbGenerated {
- get {
- return this.attrColumn != null &&
- (this.attrColumn.IsDbGenerated || !string.IsNullOrEmpty(attrColumn.Expression)) || IsVersion;
- }
- }
- public override bool IsVersion {
- get { return this.attrColumn != null && this.attrColumn.IsVersion; }
- }
- public override bool IsDiscriminator {
- get { return attrColumn == null ? false : attrColumn.IsDiscriminator; }
- }
- public override bool CanBeNull {
- get {
- if (this.attrColumn == null) {
- return true;
- }
- if (!this.attrColumn.CanBeNullSet) {
- return this.isNullableType || !this.type.IsValueType;
- }
- return this.attrColumn.CanBeNull;
- }
- }
- public override string DbType {
- get {
- if (this.attrColumn != null) {
- return this.attrColumn.DbType;
- }
- return null;
- }
- }
- public override string Expression {
- get {
- if (this.attrColumn != null) {
- return this.attrColumn.Expression;
- }
- return null;
- }
- }
- public override string MappedName {
- get {
- if (this.attrColumn != null && this.attrColumn.Name != null) {
- return this.attrColumn.Name;
- }
- if (this.attrAssoc != null && this.attrAssoc.Name != null) {
- return this.attrAssoc.Name;
- }
- return this.member.Name;
- }
- }
- public override UpdateCheck UpdateCheck {
- get {
- if (this.attrColumn != null) {
- return this.attrColumn.UpdateCheck;
- }
- return UpdateCheck.Never;
- }
- }
- public override AutoSync AutoSync {
- get {
- if (this.attrColumn != null) {
- // auto-gen keys are always and only synced on insert
- if (this.IsDbGenerated && this.IsPrimaryKey) {
- return AutoSync.OnInsert;
- }
- // if the user has explicitly set it, use their value
- if (attrColumn.AutoSync != AutoSync.Default) {
- return attrColumn.AutoSync;
- }
- // database generated members default to always
- if (this.IsDbGenerated) {
- return AutoSync.Always;
- }
- }
- return AutoSync.Never;
- }
- }
- public override MetaAssociation Association {
- get {
- if (this.IsAssociation) {
- // LOCKING: This deferral isn't an optimization. It can't be done in the constructor
- // because there may be loops in the association graph.
- if (this.assoc == null) {
- lock (this.locktarget) {
- if (this.assoc == null) {
- this.assoc = new AttributedMetaAssociation(this, this.attrAssoc);
- }
- }
- }
- }
- return this.assoc;
- }
- }
- public override MethodInfo LoadMethod {
- get {
- if (this.hasLoadMethod == false && (this.IsDeferred || this.IsAssociation)) {
- // defer searching for this access method until we really need to know
- this.loadMethod = MethodFinder.FindMethod(
- ((AttributedMetaModel)this.metaType.Model).ContextType,
- "Load" + this.member.Name,
- BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
- new Type[] { this.DeclaringType.Type }
- );
- this.hasLoadMethod = true;
- }
- return this.loadMethod;
- }
- }
- private bool IsDeferredType(Type entityType) {
- if (entityType == null || entityType == typeof(object)) {
- return false;
- }
- if (entityType.IsGenericType) {
- Type gtype = entityType.GetGenericTypeDefinition();
- return gtype == typeof(Link<>) ||
- typeof(EntitySet<>).IsAssignableFrom(gtype) ||
- typeof(EntityRef<>).IsAssignableFrom(gtype) ||
- IsDeferredType(entityType.BaseType);
- }
- return false;
- }
- private static MetaAccessor MakeMemberAccessor(Type accessorType, MemberInfo mi, MetaAccessor storage) {
- FieldInfo fi = mi as FieldInfo;
- MetaAccessor acc = null;
- if (fi != null) {
- acc = FieldAccessor.Create(accessorType, fi);
- }
- else {
- PropertyInfo pi = (PropertyInfo)mi;
- acc = PropertyAccessor.Create(accessorType, pi, storage);
- }
- return acc;
- }
- [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
- private static void MakeDeferredAccessors(
- Type objectDeclaringType, MetaAccessor accessor,
- out MetaAccessor accessorValue, out MetaAccessor accessorDeferredValue, out MetaAccessor accessorDeferredSource
- ) {
- if (accessor.Type.IsGenericType) {
- Type gtype = accessor.Type.GetGenericTypeDefinition();
- Type itemType = accessor.Type.GetGenericArguments()[0];
- if (gtype == typeof(Link<>)) {
- accessorValue = CreateAccessor(typeof(LinkValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- accessorDeferredValue = CreateAccessor(typeof(LinkDefValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- accessorDeferredSource = CreateAccessor(typeof(LinkDefSourceAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- return;
- }
- else if (typeof(EntityRef<>).IsAssignableFrom(gtype)) {
- accessorValue = CreateAccessor(typeof(EntityRefValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- accessorDeferredValue = CreateAccessor(typeof(EntityRefDefValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- accessorDeferredSource = CreateAccessor(typeof(EntityRefDefSourceAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- return;
- }
- else if (typeof(EntitySet<>).IsAssignableFrom(gtype)) {
- accessorValue = CreateAccessor(typeof(EntitySetValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- accessorDeferredValue = CreateAccessor(typeof(EntitySetDefValueAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- accessorDeferredSource = CreateAccessor(typeof(EntitySetDefSourceAccessor<,>).MakeGenericType(objectDeclaringType, itemType), accessor);
- return;
- }
- }
- throw Error.UnhandledDeferredStorageType(accessor.Type);
- }
- private static MetaAccessor CreateAccessor(Type accessorType, params object[] args) {
- return (MetaAccessor)Activator.CreateInstance(accessorType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, args, null);
- }
- public override string ToString() {
- return this.DeclaringType.ToString() + ":" + this.Member.ToString();
- }
- }
- internal class AttributedMetaAssociation : MetaAssociationImpl {
- AttributedMetaDataMember thisMember;
- MetaDataMember otherMember;
- ReadOnlyCollection<MetaDataMember> thisKey;
- ReadOnlyCollection<MetaDataMember> otherKey;
- MetaType otherType;
- bool isMany;
- bool isForeignKey;
- bool isUnique;
- bool isNullable = true;
- bool thisKeyIsPrimaryKey;
- bool otherKeyIsPrimaryKey;
- string deleteRule;
- bool deleteOnNull;
- internal AttributedMetaAssociation(AttributedMetaDataMember member, AssociationAttribute attr) {
- this.thisMember = member;
- this.isMany = TypeSystem.IsSequenceType(this.thisMember.Type);
- Type ot = this.isMany ? TypeSystem.GetElementType(this.thisMember.Type) : this.thisMember.Type;
- this.otherType = this.thisMember.DeclaringType.Model.GetMetaType(ot);
- this.thisKey = (attr.ThisKey != null) ? MakeKeys(this.thisMember.DeclaringType, attr.ThisKey) : this.thisMember.DeclaringType.IdentityMembers;
- this.otherKey = (attr.OtherKey != null) ? MakeKeys(otherType, attr.OtherKey) : this.otherType.IdentityMembers;
- this.thisKeyIsPrimaryKey = AreEqual(this.thisKey, this.thisMember.DeclaringType.IdentityMembers);
- this.otherKeyIsPrimaryKey = AreEqual(this.otherKey, this.otherType.IdentityMembers);
- this.isForeignKey = attr.IsForeignKey;
- this.isUnique = attr.IsUnique;
- this.deleteRule = attr.DeleteRule;
- this.deleteOnNull = attr.DeleteOnNull;
- // if any key members are not nullable, the association is not nullable
- foreach (MetaDataMember mm in thisKey) {
- if (!mm.CanBeNull) {
- this.isNullable = false;
- break;
- }
- }
- // validate DeleteOnNull specification
- if (deleteOnNull == true) {
- if( !(isForeignKey && !isMany && !isNullable) ) {
- throw Error.InvalidDeleteOnNullSpecification(member);
- }
- }
- //validate the number of ThisKey columns is the same as the number of OtherKey columns
- if (this.thisKey.Count != this.otherKey.Count && this.thisKey.Count > 0 && this.otherKey.Count > 0) {
- throw Error.MismatchedThisKeyOtherKey(member.Name, member.DeclaringType.Name);
- }
- // determine reverse reference member
- foreach (MetaDataMember omm in this.otherType.PersistentDataMembers) {
- AssociationAttribute oattr = (AssociationAttribute)Attribute.GetCustomAttribute(omm.Member, typeof(AssociationAttribute));
- if (oattr != null) {
- if (omm != this.thisMember && oattr.Name == attr.Name) {
- this.otherMember = omm;
- break;
- }
- }
- }
- }
- public override MetaType OtherType {
- get { return this.otherType; }
- }
- public override MetaDataMember ThisMember {
- get { return this.thisMember; }
- }
- public override MetaDataMember OtherMember {
- get { return this.otherMember; }
- }
- public override ReadOnlyCollection<MetaDataMember> ThisKey {
- get { return this.thisKey; }
- }
- public override ReadOnlyCollection<MetaDataMember> OtherKey {
- get { return this.otherKey; }
- }
- public override bool ThisKeyIsPrimaryKey {
- get { return this.thisKeyIsPrimaryKey; }
- }
- public override bool OtherKeyIsPrimaryKey {
- get { return this.otherKeyIsPrimaryKey; }
- }
- public override bool IsMany {
- get { return this.isMany; }
- }
- public override bool IsForeignKey {
- get { return this.isForeignKey; }
- }
- public override bool IsUnique {
- get { return this.isUnique; }
- }
- public override bool IsNullable {
- get { return this.isNullable; }
- }
- public override string DeleteRule {
- get { return this.deleteRule; }
- }
- public override bool DeleteOnNull {
- get { return this.deleteOnNull; }
- }
- }
- }
|