/// <summary> /// Returns a list of keys from the given meta type based on the key list string. /// </summary> /// <param name="keyListString">The key list string.</param> /// <param name="parentType">Type of the parent.</param> /// <returns></returns> private static ReadOnlyCollection<MetaDataMember> GetKeys(string keyListString, MetaType parentType) { if(keyListString != null) { var thisKeyList = new List<MetaDataMember>(); string[] keyNames = keyListString.Split(STRING_SEPERATOR, StringSplitOptions.RemoveEmptyEntries); foreach (string rawKeyName in keyNames) { string keyName = rawKeyName.Trim(); //TODO: maybe speed the lookup up MetaDataMember key = (from dataMember in parentType.PersistentDataMembers where dataMember.Name == keyName select dataMember).SingleOrDefault(); if(key == null) { 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.", keyName, keyListString, parentType.Type.Name); throw new InvalidOperationException(errorMessage); } thisKeyList.Add(key); } return new ReadOnlyCollection<MetaDataMember>(thisKeyList); } else //Key is the primary key of this table { return parentType.IdentityMembers; } }
public AttributedColumnMetaDataMember(MemberInfo member, ColumnAttribute attribute, MetaType declaringType) : base(member, declaringType, attribute) { columnAttribute = attribute; if (columnAttribute.Name == null) columnAttribute.Name = memberInfo.Name; }
internal SqlTable(MetaTable table, MetaType rowType, ProviderType sqlRowType, Expression sourceExpression) : base(SqlNodeType.Table, sourceExpression) { this.table = table; this.rowType = rowType; this.sqlRowType = sqlRowType; this.columns = new List<SqlColumn>(); }
public AttributedColumnMetaDataMember(MemberInfo member, ColumnAttribute attribute, MetaType declaringType) : base(member, declaringType, member.DeclaringType.GetSingleMember(attribute.Storage)) { columnAttribute = attribute; if (columnAttribute.Name == null) columnAttribute.Name = memberInfo.Name; }
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; } } }
public DLinqTableProvider(DLinqDataModelProvider dataModel, MetaType rowType, string name, PropertyInfo prop) : base(dataModel) { _prop = prop; _rowType = rowType; Name = name; DataContextPropertyName = prop.Name; EntityType = rowType.Type; ParentEntityType = rowType.InheritanceBase != null ? rowType.InheritanceBase.Type : null; RootEntityType = rowType.Table.RowType.Type; _columns = new List<ColumnProvider>(); var members = new List<MetaDataMember>(rowType.DataMembers); // Add in base-class-first order (not the typical derived-class-first order) foreach (PropertyInfo propInfo in GetOrderedProperties(rowType.Type)) { MetaDataMember member = members.FirstOrDefault(m => m.Member.Name == propInfo.Name); if (member != null) { AddColumn(dataModel, member, propInfo); members.Remove(member); } } // Anything we might've missed, tack it onto the end foreach (MetaDataMember member in members) { AddColumn(dataModel, member, (PropertyInfo)member.Member); } _roColumns = new ReadOnlyCollection<ColumnProvider>(_columns); }
internal UnmappedDataMember(MetaType declaringType, MemberInfo mi, int ordinal) { this.declaringType = declaringType; this.member = mi; this.ordinal = ordinal; this.type = TypeSystem.GetMemberType(mi); }
/// <summary> /// Given a type root and a discriminator, return the type that would be instantiated. /// </summary> private static MetaType TypeFromDiscriminator(MetaType root, object discriminator) { foreach (MetaType type in root.InheritanceTypes) { if (IsSameDiscriminator(discriminator, type.InheritanceCode)) return type; } return root.InheritanceDefault; }
public RepositoryMetaType(string workspace, MetaType original, MetaTable table, MetaModel metaModel) { this.Workspace = workspace; this.Original = original; this.RepositoryMetaTable = table; this.RepositoryMetaModel = metaModel; }
public override bool IsDeclaredBy(MetaType metaType) { if(metaType == null) { throw Error.ArgumentNull("metaType"); } return metaType.Type == this.member.DeclaringType; }
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; } } } }
internal MappedDataMember(MetaType declaringType, MemberInfo mi, MemberMapping map, int ordinal) { this.declaringType = declaringType; this.member = mi; this.ordinal = ordinal; this.type = TypeSystem.GetMemberType(mi); this.isNullableType = TypeSystem.IsNullableType(this.type); this.memberMap = map; if(this.memberMap != null && this.memberMap.StorageMemberName != null) { MemberInfo[] mis = mi.DeclaringType.GetMember(this.memberMap.StorageMemberName, BindingFlags.Instance | BindingFlags.NonPublic); if(mis == null || mis.Length != 1) { throw Error.BadStorageProperty(this.memberMap.StorageMemberName, mi.DeclaringType, mi.Name); } this.storageMember = mis[0]; } Type storageType = this.storageMember != null ? TypeSystem.GetMemberType(this.storageMember) : this.type; this.isDeferred = IsDeferredType(storageType); ColumnMapping cmap = map as ColumnMapping; if(cmap != null && cmap.IsDbGenerated && cmap.IsPrimaryKey) { // auto-gen identities must be synced on insert if((cmap.AutoSync != AutoSync.Default) && (cmap.AutoSync != AutoSync.OnInsert)) { throw Error.IncorrectAutoSyncSpecification(mi.Name); } } if(cmap != null) { this.isPrimaryKey = cmap.IsPrimaryKey; this.isVersion = cmap.IsVersion; this.isDBGenerated = cmap.IsDbGenerated || !string.IsNullOrEmpty(cmap.Expression) || this.isVersion; this.isDiscriminator = cmap.IsDiscriminator; this.canBeNull = cmap.CanBeNull == null ? this.isNullableType || !this.type.IsValueType : (bool)cmap.CanBeNull; this.dbType = cmap.DbType; this.expression = cmap.Expression; this.updateCheck = cmap.UpdateCheck; // auto-gen keys are always and only synced on insert if(this.IsDbGenerated && this.IsPrimaryKey) { this.autoSync = AutoSync.OnInsert; } else if(cmap.AutoSync != AutoSync.Default) { // if the user has explicitly set it, use their value this.autoSync = cmap.AutoSync; } else if(this.IsDbGenerated) { // database generated members default to always this.autoSync = AutoSync.Always; } } this.mappedName = this.memberMap.DbName != null ? this.memberMap.DbName : this.member.Name; }
internal SqlDiscriminatedType(ProviderType sqlType, SqlExpression discriminator, MetaType targetType, Expression sourceExpression) : base(SqlNodeType.DiscriminatedType, typeof(Type), sourceExpression) { if (discriminator == null) throw Error.ArgumentNull("discriminator"); this.discriminator = discriminator; this.targetType = targetType; this.sqlType = sqlType; }
internal SqlTypeCase(Type clrType, ProviderType sqlType, MetaType rowType, SqlExpression discriminator, IEnumerable<SqlTypeCaseWhen> whens, Expression sourceExpression) : base(SqlNodeType.TypeCase, clrType, sourceExpression) { this.Discriminator = discriminator; if (whens == null) throw Error.ArgumentNull("whens"); this.whens.AddRange(whens); if (this.whens.Count == 0) throw Error.ArgumentOutOfRange("whens"); this.sqlType = sqlType; this.rowType = rowType; }
internal SqlLink(object id, MetaType rowType, Type clrType, ProviderType sqlType, SqlExpression expression, MetaDataMember member, IEnumerable<SqlExpression> keyExpressions, SqlExpression expansion, Expression sourceExpression) : base(SqlNodeType.Link, clrType, sqlType, sourceExpression) { this.id = id; this.rowType = rowType; this.expansion = expansion; this.expression = expression; this.member = member; this.keyExpressions = new List<SqlExpression>(); if (keyExpressions != null) this.keyExpressions.AddRange(keyExpressions); }
private object locktarget = new object(); // Hold locks on private object rather than public MetaType. #endregion internal MappedType(MetaModel model, MetaTable table, TypeMapping typeMapping, Type type, MetaType inheritanceRoot) { this.model = model; this.table = table; this.typeMapping = typeMapping; this.type = type; this.inheritanceRoot = inheritanceRoot != null ? inheritanceRoot : this; this.InitDataMembers(); this.identities = this.dataMembers.Where(m => m.IsPrimaryKey).ToList().AsReadOnly(); this.persistentDataMembers = this.dataMembers.Where(m => m.IsPersistent).ToList().AsReadOnly(); }
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(); }
internal SqlSelect BuildDefaultQuery(MetaType rowType, bool allowDeferred, SqlLink link, Expression source) { System.Diagnostics.Debug.Assert(rowType != null && rowType.Table != null); if (rowType.HasInheritance && rowType.InheritanceRoot != rowType) { // RowType is expected to be an inheritance root. throw Error.ArgumentWrongValue("rowType"); } SqlTable table = sql.Table(rowType.Table, rowType, source); SqlAlias tableAlias = new SqlAlias(table); SqlAliasRef tableAliasRef = new SqlAliasRef(tableAlias); SqlExpression projection = this.BuildProjection(tableAliasRef, table.RowType, allowDeferred, link, source); return new SqlSelect(projection, tableAlias, source); }
protected AttributedAbstractMetaDataMember(MemberInfo member, MetaType declaringType, DataAttribute attribute) { memberInfo = member; memberAccessor = LambdaMetaAccessor.Create(member, declaringType.Type); this.declaringType = declaringType; if(attribute.Storage != null) { storageMember = member.DeclaringType.GetSingleMember(attribute.Storage); if (storageMember != null) storageAccessor = LambdaMetaAccessor.Create(storageMember, declaringType.Type); } }
public AttributedMetaTable(TableAttribute attribute, MetaType type, MetaModel model) { _tableAttribute = attribute; _metaType = type; _containingModel = model; //If the attribute doesn't specify a table name the name of the table class is used if(!string.IsNullOrEmpty(attribute.Name)) { _tableName = attribute.Name; } else { _tableName = type.Name; } }
private void SetCurrent(MetaType type) { type = type.InheritanceRoot; if(this.currentType != type) { if(!this.caches.TryGetValue(type, out this.currentCache)) { KeyManager km = GetKeyManager(type); this.currentCache = (IdentityCache)Activator.CreateInstance( typeof(IdentityCache<,>).MakeGenericType(type.Type, km.KeyType), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[] { km }, null ); this.caches.Add(type, this.currentCache); } this.currentType = type; } }
/// <summary> /// Given a MetaType and a set of key fields, return the set of MetaDataMembers /// corresponding to the key. /// </summary> protected static ReadOnlyCollection<MetaDataMember> MakeKeys(MetaType mtype, string keyFields) { string[] names = keyFields.Split(keySeparators); MetaDataMember[] members = new MetaDataMember[names.Length]; for(int i = 0; i < names.Length; i++) { names[i] = names[i].Trim(); MemberInfo[] rmis = mtype.Type.GetMember(names[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if(rmis == null || rmis.Length != 1) { throw Error.BadKeyMember(names[i], keyFields, mtype.Name); } members[i] = mtype.GetDataMember(rmis[0]); if(members[i] == null) { throw Error.BadKeyMember(names[i], keyFields, mtype.Name); } } return new List<MetaDataMember>(members).AsReadOnly(); }
private void InitOther() { if(this.otherType == null) { Type ot = this.isMany ? TypeSystem.GetElementType(this.thisMember.Type) : this.thisMember.Type; this.otherType = this.thisMember.DeclaringType.Model.GetMetaType(ot); System.Diagnostics.Debug.Assert(this.otherType.IsEntity); this.otherKey = (assocMap.OtherKey != null) ? MakeKeys(this.otherType, this.assocMap.OtherKey) : this.otherType.IdentityMembers; this.otherKeyIsPrimaryKey = AreEqual(this.otherKey, this.otherType.IdentityMembers); foreach(MetaDataMember omm in this.otherType.DataMembers) { if(omm.IsAssociation && omm != this.thisMember && omm.MappedName == this.thisMember.MappedName) { this.otherMember = omm; break; } } } }
internal SqlNew(MetaType metaType, ProviderType sqlType, ConstructorInfo cons, IEnumerable<SqlExpression> args, IEnumerable<MemberInfo> argMembers, IEnumerable<SqlMemberAssign> members, Expression sourceExpression) : base(SqlNodeType.New, metaType.Type, sqlType, sourceExpression) { this.metaType = metaType; if (cons == null && metaType.Type.IsClass) { // structs do not need to have a constructor throw Error.ArgumentNull("cons"); } this.constructor = cons; this.args = new List<SqlExpression>(); this.argMembers = new List<MemberInfo>(); this.members = new List<SqlMemberAssign>(); if (args != null) { this.args.AddRange(args); } if (argMembers != null) { this.argMembers.AddRange(argMembers); } if (members != null) { this.members.AddRange(members); } }
static KeyManager GetKeyManager(MetaType type) { int n = type.IdentityMembers.Count; MetaDataMember mm = type.IdentityMembers[0]; KeyManager km = (KeyManager)Activator.CreateInstance( typeof(SingleKeyManager<,>).MakeGenericType(type.Type, mm.Type), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[] { mm.StorageAccessor, 0 }, null ); for(int i = 1; i < n; i++) { mm = type.IdentityMembers[i]; km = (KeyManager) Activator.CreateInstance( typeof(MultiKeyManager<,,>).MakeGenericType(type.Type, mm.Type, km.KeyType), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[] { mm.StorageAccessor, i, km }, null ); } return km; }
private TrackedObject Track(MetaType mt, object obj, Dictionary<object, object> visited, bool recurse, int level) { StandardTrackedObject tracked = (StandardTrackedObject)this.GetTrackedObject(obj); if(tracked != null || visited.ContainsKey(obj)) { return tracked; } // The root object tracked is tracked normally - all other objects // in the reference graph are weakly tracked. bool weaklyTrack = level > 1; tracked = new StandardTrackedObject(this, mt, obj, obj, weaklyTrack); if(tracked.HasDeferredLoaders) { throw Error.CannotAttachAddNonNewEntities(); } this.items.Add(obj, tracked); this.Attach(obj); visited.Add(obj, obj); if(recurse) { // track parents (objects we are dependent on) foreach(RelatedItem parent in this.services.GetParents(mt, obj)) { this.Track(parent.Type, parent.Item, visited, recurse, level + 1); } // track children (objects that are dependent on us) foreach(RelatedItem child in this.services.GetChildren(mt, obj)) { this.Track(child.Type, child.Item, visited, recurse, level + 1); } } return tracked; }
internal SqlExpression BuildProjection(SqlExpression item, MetaType rowType, bool allowDeferred, SqlLink link, Expression source) { if (!rowType.HasInheritance) { return this.BuildProjectionInternal(item, rowType, (rowType.Table != null) ? rowType.PersistentDataMembers : rowType.DataMembers, allowDeferred, link, source); } else { // Build a type case that represents a switch between the various type. List<MetaType> mappedTypes = new List<MetaType>(rowType.InheritanceTypes); List<SqlTypeCaseWhen> whens = new List<SqlTypeCaseWhen>(); SqlTypeCaseWhen @else = null; MetaType root = rowType.InheritanceRoot; MetaDataMember discriminator = root.Discriminator; Type dt = discriminator.Type; SqlMember dm = sql.Member(item, discriminator.Member); foreach (MetaType type in mappedTypes) { if (type.HasInheritanceCode) { SqlNew defaultProjection = this.BuildProjectionInternal(item, type, type.PersistentDataMembers, allowDeferred, link, source); if (type.IsInheritanceDefault) { @else = new SqlTypeCaseWhen(null, defaultProjection); } // Add an explicit case even for the default. // Redundant results will be optimized out later. object code = InheritanceRules.InheritanceCodeForClientCompare(type.InheritanceCode, dm.SqlType); SqlExpression match = sql.Value(dt, sql.Default(discriminator), code, true, source); whens.Add(new SqlTypeCaseWhen(match, defaultProjection)); } } if (@else == null) { throw Error.EmptyCaseNotSupported(); } whens.Add(@else); // Add the else at the end. return sql.TypeCase(root.Type, root, dm, whens.ToArray(), source); } }
private void ObserveUntrackedObjects(MetaType type, object item, Dictionary<object, object> visited) { if (!visited.ContainsKey(item)) { visited.Add(item, item); TrackedObject tracked = this.tracker.GetTrackedObject(item); if (tracked == null) { tracked = this.tracker.Track(item); tracked.ConvertToNew(); } else if (tracked.IsDead || tracked.IsRemoved) { // ignore return; } // search parents (objects we are dependent on) foreach (RelatedItem parent in this.services.GetParents(type, item)) { this.ObserveUntrackedObjects(parent.Type, parent.Item, visited); } // synch up primary key unless its generated. if (tracked.IsNew) { if (!tracked.IsPendingGeneration(tracked.Type.IdentityMembers)) { tracked.SynchDependentData(); } } // search children (objects that are dependent on us) foreach (RelatedItem child in this.services.GetChildren(type, item)) { this.ObserveUntrackedObjects(child.Type, child.Item, visited); } } }
private void TrackUntrackedObjects(MetaType type, object item, Dictionary<object, object> visited) { if (!visited.ContainsKey(item)) { visited.Add(item, item); TrackedObject tracked = this.tracker.GetTrackedObject(item); if (tracked == null) { tracked = this.tracker.Track(item); tracked.ConvertToNew(); } else if (tracked.IsDead || tracked.IsRemoved) { // ignore return; } // search parents (objects we are dependent on) foreach (RelatedItem parent in this.services.GetParents(type, item)) { this.TrackUntrackedObjects(parent.Type, parent.Item, visited); } // synch up primary key if (tracked.IsNew) { tracked.InitializeDeferredLoaders(); if (!tracked.IsPendingGeneration(tracked.Type.IdentityMembers)) { tracked.SynchDependentData(); object cached = this.services.InsertLookupCachedObject(tracked.Type, item); if (cached != item) { TrackedObject cachedTracked = this.tracker.GetTrackedObject(cached); Debug.Assert(cachedTracked != null); if (cachedTracked.IsDeleted || cachedTracked.CanInferDelete()) { // adding new object with same ID as object being deleted.. turn into modified tracked.ConvertToPossiblyModified(cachedTracked.Original); // turn deleted to dead... cachedTracked.ConvertToDead(); this.services.RemoveCachedObjectLike(tracked.Type, item); this.services.InsertLookupCachedObject(tracked.Type, item); } else if (!cachedTracked.IsDead) { throw new DuplicateKeyException(item, Strings.CantAddAlreadyExistingKey); } } } else { // we may have a generated PK, however we set the PK on this new item to // match a deleted item object cached = this.services.GetCachedObjectLike(tracked.Type, item); if (cached != null) { TrackedObject cachedTracked = this.tracker.GetTrackedObject(cached); Debug.Assert(cachedTracked != null); if (cachedTracked.IsDeleted || cachedTracked.CanInferDelete()) { // adding new object with same ID as object being deleted.. turn into modified tracked.ConvertToPossiblyModified(cachedTracked.Original); // turn deleted to dead... cachedTracked.ConvertToDead(); this.services.RemoveCachedObjectLike(tracked.Type, item); this.services.InsertLookupCachedObject(tracked.Type, item); } } } } // search children (objects that are dependent on us) foreach (RelatedItem child in this.services.GetChildren(type, item)) { this.TrackUntrackedObjects(child.Type, child.Item, visited); } } }
private static void SendOnValidate(MetaType type, TrackedObject item, ChangeAction changeAction) { if (type != null) { SendOnValidate(type.InheritanceBase, item, changeAction); if (type.OnValidateMethod != null) { try { type.OnValidateMethod.Invoke(item.Current, new object[] { changeAction }); } catch (TargetInvocationException tie) { if (tie.InnerException != null) { throw tie.InnerException; } throw; } } } }
public abstract bool IsDeclaredBy(MetaType type);