/// <summary> /// Returns a unique association name for the specified MetaAssociation /// </summary> /// <param name="metaAssociation">A <see cref="MetaAssociation"/>.</param> /// <returns>A <see cref="String"/> containing the association name.</returns> private string GetAssociationName(MetaAssociation metaAssociation) { lock (this._associationNameMap) { // We need a unique key for this association, so we use the MetaAssociation // itself. In the case of bi-directional associations, we use the FK side. if (!metaAssociation.IsForeignKey && metaAssociation.OtherMember != null) { metaAssociation = metaAssociation.OtherMember.Association; } string associationName = null; if (!this._associationNameMap.TryGetValue(metaAssociation, out associationName)) { // names are always formatted non-FK side type name followed by FK side type name // For example, the name for both ends of the PurchaseOrder/PurchaseOrderDetail // association will be PurchaseOrder_PurchaseOrderDetail if (metaAssociation.IsForeignKey) { associationName = string.Format(CultureInfo.InvariantCulture, "{0}_{1}", metaAssociation.OtherType.Name, metaAssociation.ThisMember.DeclaringType.Name); } else { associationName = string.Format(CultureInfo.InvariantCulture, "{0}_{1}", metaAssociation.ThisMember.DeclaringType.Name, metaAssociation.OtherType.Name); } associationName = TypeDescriptionContextBase.MakeUniqueName(associationName, this._associationNameMap.Values); this._associationNameMap[metaAssociation] = associationName; } return associationName; } }
private void SetAssociationKeyInfo(MetaAssociation association) { DLinqColumnProvider column = (DLinqColumnProvider)FromColumn; List<string> foreignKeyNames = new List<string>(); int count = column.Member.Association.ThisKey.Count; for (int i = 0; i < count; i++) { MetaDataMember thisKeyMetaDataMember = column.Member.Association.ThisKey[i]; MetaDataMember otherKeyMetaDataMember = column.Member.Association.OtherKey[i]; DLinqColumnProvider thisEntityMemberComponent = FindColumn(column.Table, thisKeyMetaDataMember.Name); if (ShouldRemoveThisAssociation(association)) { column.ShouldRemove = true; return; } foreignKeyNames.Add(thisEntityMemberComponent.Name); if (thisEntityMemberComponent.IsPrimaryKey) { IsPrimaryKeyInThisTable = true; } if (association.IsForeignKey) { thisEntityMemberComponent.IsForeignKeyComponent = true; } } ForeignKeyNames = new ReadOnlyCollection<string>(foreignKeyNames); }
private void SetOtherEndOfAssociation(MetaAssociation association) { DLinqTableProvider entityMemberParentEntity = (DLinqTableProvider)FromColumn.Table; DLinqDataModelProvider parentEntityDataContext = (DLinqDataModelProvider)entityMemberParentEntity.DataModel; if (association.OtherMember != null) { ToColumn = parentEntityDataContext.ColumnLookup[(PropertyInfo)association.OtherMember.Member]; } else { ToTable = ((DLinqDataModelProvider)FromColumn.Table.DataModel).DLinqTables.Single(tp => tp.EntityType == association.OtherType.Type); } }
internal void Add(MetaAssociation assoc, TrackedObject from, TrackedObject to) { Dictionary<TrackedObject, TrackedObject> pairs; if(!associations.TryGetValue(assoc, out pairs)) { pairs = new Dictionary<TrackedObject, TrackedObject>(); associations.Add(assoc, pairs); } pairs.Add(from, to); }
internal RelationComposer(ParameterExpression parameter, MetaAssociation association, Expression otherSouce, Expression parameterReplacement) { if (parameter==null) throw Error.ArgumentNull("parameter"); if (association == null) throw Error.ArgumentNull("association"); if (otherSouce == null) throw Error.ArgumentNull("otherSouce"); if (parameterReplacement==null) throw Error.ArgumentNull("parameterReplacement"); this.parameter = parameter; this.association = association; this.otherSouce = otherSouce; this.parameterReplacement = parameterReplacement; }
internal TrackedObject this[MetaAssociation assoc, TrackedObject from] { get { Dictionary<TrackedObject, TrackedObject> pairs; if(associations.TryGetValue(assoc, out pairs)) { TrackedObject to; if(pairs.TryGetValue(from, out to)) { return to; } } return null; } }
private bool ShouldRemoveThisAssociation(MetaAssociation association) { if (Direction == AssociationDirection.ManyToOne && !association.OtherKeyIsPrimaryKey) { return true; } if (Direction == AssociationDirection.OneToMany && !association.ThisKeyIsPrimaryKey) { return true; } if (Direction == AssociationDirection.OneToOne) { if (!association.IsForeignKey && !association.ThisKeyIsPrimaryKey) { return true; } if (association.IsForeignKey && !association.OtherKeyIsPrimaryKey) { return true; } } return false; }
private bool HasAssociationChanged(MetaAssociation assoc, TrackedObject item) { if (item.Original != null && item.Current != null) { if (assoc.ThisMember.StorageAccessor.HasAssignedValue(item.Current) || assoc.ThisMember.StorageAccessor.HasLoadedValue(item.Current) ) { return this.GetOtherItem(assoc, item.Current) != this.GetOtherItem(assoc, item.Original); } else { object[] currentFKs = CommonDataServices.GetForeignKeyValues(assoc, item.Current); object[] originaFKs = CommonDataServices.GetForeignKeyValues(assoc, item.Original); for (int i = 0, n = currentFKs.Length; i < n; i++) { if (!object.Equals(currentFKs[i], originaFKs[i])) return true; } } } return false; }
private TrackedObject GetOtherItem(MetaAssociation assoc, object instance) { if (instance == null) return null; object other = null; // Don't load unloaded references if (assoc.ThisMember.StorageAccessor.HasAssignedValue(instance) || assoc.ThisMember.StorageAccessor.HasLoadedValue(instance) ) { other = assoc.ThisMember.MemberAccessor.GetBoxedValue(instance); } else if (assoc.OtherKeyIsPrimaryKey) { // Maybe it's in the cache, but not yet attached through reference. object[] foreignKeys = CommonDataServices.GetForeignKeyValues(assoc, instance); other = this.services.GetCachedObject(assoc.OtherType, foreignKeys); } // else the other key is not the primary key so there is no way to try to look it up return (other != null) ? this.tracker.GetTrackedObject(other) : null; }
// Ensure the the member and foreign keys are nulled so that after trackedInstance is deleted, // the object does not appear to be associated with the other side anymore. This prevents the deleted object // from referencing objects still in the cache, but also will prevent the related object from being implicitly loaded private static void ClearForeignKeysHelper(MetaAssociation assoc, object trackedInstance) { Debug.Assert(assoc.IsForeignKey, "Foreign key clearing should only happen on foreign key side of the association."); Debug.Assert(assoc.ThisMember.IsAssociation, "Expected ThisMember of an association to always be an association."); // If this member is one of our deferred loaders, and it does not already have a value, explicitly set the deferred source to // null so that when we set the association member itself to null later, it doesn't trigger an implicit load. // This is only necessary if the value has not already been assigned or set, because otherwise we won't implicitly load anyway when the member is accessed. MetaDataMember thisMember = assoc.ThisMember; if (thisMember.IsDeferred && !(thisMember.StorageAccessor.HasAssignedValue(trackedInstance) || thisMember.StorageAccessor.HasLoadedValue(trackedInstance))) { // If this is a deferred member, set the value directly in the deferred accessor instead of going // through the normal member accessor, so that we don't trigger an implicit load. thisMember.DeferredSourceAccessor.SetBoxedValue(ref trackedInstance, null); } // Notify the object that the relationship should be considered deleted. // This allows the object to do its own fixup even when we can't do it automatically. thisMember.MemberAccessor.SetBoxedValue(ref trackedInstance, null); // Also set the foreign key values to null if possible for (int i = 0, n = assoc.ThisKey.Count; i < n; i++) { MetaDataMember thisKey = assoc.ThisKey[i]; if (thisKey.CanBeNull) { thisKey.StorageAccessor.SetBoxedValue(ref trackedInstance, null); } } }
public void SetAssociation(MetaAssociation association) { metaAssociation = association; }
/// <summary> /// Create an Expression representing the given association and key value expressions. /// </summary> internal static Expression TranslateAssociation(DataContext context, MetaAssociation association, Expression otherSource, Expression[] keyValues, Expression thisInstance) { if (association == null) throw Error.ArgumentNull("association"); if (keyValues == null) throw Error.ArgumentNull("keyValues"); if (context.LoadOptions!=null) { LambdaExpression subquery = context.LoadOptions.GetAssociationSubquery(association.ThisMember.Member); if (subquery!=null) { RelationComposer rc = new RelationComposer(subquery.Parameters[0], association, otherSource, thisInstance); return rc.Visit(subquery.Body); } } return WhereClauseFromSourceAndKeys(otherSource, association.OtherKey.ToArray(), keyValues); }
private void SetDirection(MetaAssociation association) { if (association.IsMany) { Direction = AssociationDirection.OneToMany; } else if (association.OtherMember == null || association.OtherMember.Association.IsMany) { // there might not be the other member if this is a one-sided association Direction = AssociationDirection.ManyToOne; } else { Direction = AssociationDirection.OneToOne; } }