/// <summary>
 ///     Merge the discriminatorMap info we just found with what we've already found.
 ///     In practice, if either the current or the new map is from an OfTypeOnly view, we
 ///     have to avoid the optimizations.
 ///     If we have a new map that is a superset of the current map, then we can just swap
 ///     the new map for the current one.
 ///     If the current map is tha super set of the new one ther's nothing to do.
 ///     (Of course, if neither has changed, then we really don't need to look)
 /// </summary>
 internal void Merge(EntityTypeBase neededRootEntityType, bool includesSubtypes, ExplicitDiscriminatorMap discriminatorMap)
 {
     // If what we've found doesn't exactly match what we are looking for we have more work to do
     if (RootEntityType != neededRootEntityType ||
         IncludesSubTypes != includesSubtypes)
     {
         if (!IncludesSubTypes ||
             !includesSubtypes)
         {
             // If either the original or the new map is from an of-type-only view we can't
             // merge, we just have to not optimize this case.
             DiscriminatorMap = null;
         }
         if (TypeSemantics.IsSubTypeOf(RootEntityType, neededRootEntityType))
         {
             // we're asking for a super type of existing type, and what we had is a proper
             // subset of it -we can replace the existing item.
             RootEntityType   = neededRootEntityType;
             DiscriminatorMap = discriminatorMap;
         }
         if (!TypeSemantics.IsSubTypeOf(neededRootEntityType, RootEntityType))
         {
             // If either the original or the new map is from an of-type-only view we can't
             // merge, we just have to not optimize this case.
             DiscriminatorMap = null;
         }
     }
 }
Exemple #2
0
 private void CheckClearedEntryOnSpan(
     object targetValue, IEntityWrapper wrappedSource, EntityKey sourceKey, AssociationEndMember targetMember)
 {
     // If a relationship does not exist on the server but does exist on the client,
     // we may need to remove it, depending on the current state and the MergeOption
     if ((null != (object)sourceKey) &&
         (null == targetValue) &&
         (MergeOption == MergeOption.PreserveChanges ||
          MergeOption == MergeOption.OverwriteChanges))
     {
         // When the spanned value is null, it may be because the spanned association applies to a
         // subtype of the entity's type, and the entity is not actually an instance of that type.
         var       sourceEnd          = MetadataHelper.GetOtherAssociationEnd(targetMember);
         EdmType   expectedSourceType = ((RefType)sourceEnd.TypeUsage.EdmType).ElementType;
         TypeUsage entityTypeUsage;
         if (!Context.Perspective.TryGetType(wrappedSource.IdentityType, out entityTypeUsage) ||
             entityTypeUsage.EdmType.EdmEquals(expectedSourceType) ||
             TypeSemantics.IsSubTypeOf(entityTypeUsage.EdmType, expectedSourceType))
         {
             // Otherwise, the source entity is the correct type (exactly or a subtype) for the source
             // end of the spanned association, so validate that the relationhip that was spanned is
             // part of the Container owning the EntitySet of the root entity.
             // This can be done by comparing the EntitySet  of the row's entity to the relationships
             // in the Container and their AssociationSetEnd's type
             CheckClearedEntryOnSpan(sourceKey, targetMember);
         }
     }
 }
        internal DbRelatedEntityRef(
            RelationshipEndMember sourceEnd,
            RelationshipEndMember targetEnd,
            DbExpression targetEntityRef)
        {
            if (!object.ReferenceEquals((object)sourceEnd.DeclaringType, (object)targetEnd.DeclaringType))
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEndFromDifferentRelationship, nameof(targetEnd));
            }
            if (object.ReferenceEquals((object)sourceEnd, (object)targetEnd))
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEndSameAsSourceEnd, nameof(targetEnd));
            }
            if (targetEnd.RelationshipMultiplicity != RelationshipMultiplicity.One && targetEnd.RelationshipMultiplicity != RelationshipMultiplicity.ZeroOrOne)
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEndMustBeAtMostOne, nameof(targetEnd));
            }
            if (!TypeSemantics.IsReferenceType(targetEntityRef.ResultType))
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEntityNotRef, nameof(targetEntityRef));
            }
            EntityTypeBase elementType1 = TypeHelpers.GetEdmType <RefType>(targetEnd.TypeUsage).ElementType;
            EntityTypeBase elementType2 = TypeHelpers.GetEdmType <RefType>(targetEntityRef.ResultType).ElementType;

            if (!elementType1.EdmEquals((MetadataItem)elementType2) && !TypeSemantics.IsSubTypeOf((EdmType)elementType2, (EdmType)elementType1))
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEntityNotCompatible, nameof(targetEntityRef));
            }
            this._targetEntityRef = targetEntityRef;
            this._targetEnd       = targetEnd;
            this._sourceEnd       = sourceEnd;
        }
Exemple #4
0
        internal DbRelatedEntityRef(RelationshipEndMember sourceEnd, RelationshipEndMember targetEnd, DbExpression targetEntityRef)
        {
            // Validate that the specified relationship ends are:
            // 1. Non-null
            // 2. From the same metadata workspace as that used by the command tree
            DebugCheck.NotNull(sourceEnd);
            DebugCheck.NotNull(targetEnd);

            // Validate that the specified target entity ref is:
            // 1. Non-null
            DebugCheck.NotNull(targetEntityRef);

            // Validate that the specified source and target ends are:
            // 1. Declared by the same relationship type
            if (!ReferenceEquals(sourceEnd.DeclaringType, targetEnd.DeclaringType))
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEndFromDifferentRelationship, "targetEnd");
            }
            // 2. Not the same end
            if (ReferenceEquals(sourceEnd, targetEnd))
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEndSameAsSourceEnd, "targetEnd");
            }

            // Validate that the specified target end has multiplicity of at most one
            if (targetEnd.RelationshipMultiplicity != RelationshipMultiplicity.One
                &&
                targetEnd.RelationshipMultiplicity != RelationshipMultiplicity.ZeroOrOne)
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEndMustBeAtMostOne, "targetEnd");
            }

            // Validate that the specified target entity ref actually has a ref result type
            if (!TypeSemantics.IsReferenceType(targetEntityRef.ResultType))
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEntityNotRef, "targetEntityRef");
            }

            // Validate that the specified target entity is of a type that can be reached by navigating to the specified relationship end
            var endType    = TypeHelpers.GetEdmType <RefType>(targetEnd.TypeUsage).ElementType;
            var targetType = TypeHelpers.GetEdmType <RefType>(targetEntityRef.ResultType).ElementType;

            if (!endType.EdmEquals(targetType) &&
                !TypeSemantics.IsSubTypeOf(targetType, endType))
            {
                throw new ArgumentException(Strings.Cqt_RelatedEntityRef_TargetEntityNotCompatible, "targetEntityRef");
            }

            // Validation succeeded, initialize state
            _targetEntityRef = targetEntityRef;
            _targetEnd       = targetEnd;
            _sourceEnd       = sourceEnd;
        }
        // <summary>
        // Determines whether the specified { from, to } relationship end pairing represents a navigation that is
        // valid for a relationship span sourced by an instance of the specified entity type.
        // </summary>
        // <param name="compareType"> The Entity type which valid 'from' ends must reference (or a supertype of that Entity type) </param>
        // <param name="associationType"> The Association type to consider. </param>
        // <param name="fromEnd"> The candidate 'from' end, which will be checked based on the Entity type it references </param>
        // <param name="toEnd"> The candidate 'to' end, which will be checked base on the upper bound of its multiplicity </param>
        // <returns>
        // <c>True</c> if the end pairing represents a valid navigation from an instance of the specified entity type to an association end with a multiplicity upper bound of at most 1; otherwise <c>false</c>
        // </returns>
        private static bool IsValidRelationshipSpan(
            EntityType compareType, AssociationType associationType, AssociationEndMember fromEnd, AssociationEndMember toEnd)
        {
            // Only a relationship end with a multiplicity of AT MOST one may be
            // considered as the 'to' end, so that the cardinality of the result
            // of the relationship span has an upper bound of 1.
            // Therefore ends with RelationshipMultiplicity of EITHER One OR ZeroOrOne
            // are the only ends that should be considered as target ends.
            // Note that a relationship span can be sourced by an Entity that is of the same type
            // as the Entity type referenced by the 'from' end OR any type in the same branch of
            // the type hierarchy.
            //
            // For example, in the following hierarchy:
            //
            // A  (*<-->?) AOwner
            // |_B  (*<-->1) BOwner
            // |_A1  (*<-->?) A1Owner
            //   |_A2
            //     |_A3_1  (1<-->?) A3_1Owner
            //     |_A3_2  (*<-->1) A3_2Owner
            //
            // An instance of 'A' would need ALL the 'AOwner', 'BOwner', 'A1Owner', 'A3_1Owner' and 'A3_2Owner' ends
            // spanned in because an instance of 'A' could actually be an instance of A, B, A1, A2, A3_1 or A3_2.
            // An instance of 'B' would only need 'AOwner' and 'BOwner' spanned in.
            // An instance of A2 would need 'AOwner', 'A1Owner', 'A3_1Owner' and 'A3_2Owner' spanned in.
            // An instance of A3_1 would only need 'AOwner', 'A1Owner' and 'A3_1Owner' spanned in.
            //
            // In general, the rule for relationship span is:
            // - 'To' end cardinality AT MOST one
            //   AND
            //   - Referenced Entity type of 'From' end is equal to instance Entity type
            //     OR
            //   - Referenced Entity type of 'From' end is a supertype of instance Entity type
            //     OR
            //   - Referenced Entity type of 'From' end is a subtype of instance Entity type
            //     (this follows from the fact that an instance of 'A' may be an instance of any of its derived types.
            //      Navigation for a subtype relationship will return null if the Entity instance navigation source
            //      is not actually of the required subtype).
            //
            if (!associationType.IsForeignKey
                &&
                (RelationshipMultiplicity.One == toEnd.RelationshipMultiplicity ||
                 RelationshipMultiplicity.ZeroOrOne == toEnd.RelationshipMultiplicity))
            {
                var fromEntityType = (EntityType)((RefType)fromEnd.TypeUsage.EdmType).ElementType;
                return(EntityTypeEquals(compareType, fromEntityType) ||
                       TypeSemantics.IsSubTypeOf(compareType, fromEntityType) ||
                       TypeSemantics.IsSubTypeOf(fromEntityType, compareType));
            }

            return(false);
        }
        private static bool IsValidRelationshipSpan(
            EntityType compareType,
            AssociationType associationType,
            AssociationEndMember fromEnd,
            AssociationEndMember toEnd)
        {
            if (associationType.IsForeignKey || RelationshipMultiplicity.One != toEnd.RelationshipMultiplicity && toEnd.RelationshipMultiplicity != RelationshipMultiplicity.ZeroOrOne)
            {
                return(false);
            }
            EntityType elementType = (EntityType)((RefType)fromEnd.TypeUsage.EdmType).ElementType;

            if (!ObjectSpanRewriter.EntityTypeEquals((EntityTypeBase)compareType, (EntityTypeBase)elementType) && !TypeSemantics.IsSubTypeOf((EdmType)compareType, (EdmType)elementType))
            {
                return(TypeSemantics.IsSubTypeOf((EdmType)elementType, (EdmType)compareType));
            }
            return(true);
        }
Exemple #7
0
 internal void Merge(
     EntityTypeBase neededRootEntityType,
     bool includesSubtypes,
     ExplicitDiscriminatorMap discriminatorMap)
 {
     if (this.RootEntityType == neededRootEntityType && this.IncludesSubTypes == includesSubtypes)
     {
         return;
     }
     if (!this.IncludesSubTypes || !includesSubtypes)
     {
         this.DiscriminatorMap = (ExplicitDiscriminatorMap)null;
     }
     if (TypeSemantics.IsSubTypeOf((EdmType)this.RootEntityType, (EdmType)neededRootEntityType))
     {
         this.RootEntityType   = neededRootEntityType;
         this.DiscriminatorMap = discriminatorMap;
     }
     if (TypeSemantics.IsSubTypeOf((EdmType)neededRootEntityType, (EdmType)this.RootEntityType))
     {
         return;
     }
     this.DiscriminatorMap = (ExplicitDiscriminatorMap)null;
 }
        private void CheckClearedEntryOnSpan(
            object targetValue,
            IEntityWrapper wrappedSource,
            EntityKey sourceKey,
            AssociationEndMember targetMember)
        {
            if ((object)sourceKey == null || targetValue != null || this.MergeOption != MergeOption.PreserveChanges && this.MergeOption != MergeOption.OverwriteChanges)
            {
                return;
            }
            EdmType   elementType = (EdmType)((RefType)MetadataHelper.GetOtherAssociationEnd(targetMember).TypeUsage.EdmType).ElementType;
            TypeUsage outTypeUsage;

            if (this.Context.Perspective.TryGetType(wrappedSource.IdentityType, out outTypeUsage) && !outTypeUsage.EdmType.EdmEquals((MetadataItem)elementType) && !TypeSemantics.IsSubTypeOf(outTypeUsage.EdmType, elementType))
            {
                return;
            }
            this.CheckClearedEntryOnSpan(sourceKey, targetMember);
        }