/// <summary> /// Performs projection for a single row. Evaluates each projection argument against the specified /// row, returning a result with the specified type. /// </summary> /// <param name="node">Projection expression.</param> /// <param name="row">Row to project.</param> /// <param name="resultType">Type of the projected row.</param> /// <returns>Projected row.</returns> private PropagatorResult Project(DbProjectExpression node, PropagatorResult row, TypeUsage resultType) { EntityUtil.CheckArgumentNull(node, "node"); Debug.Assert(null != node.Projection, "CQT validates DbProjectExpression.Projection property"); DbNewInstanceExpression projection = node.Projection as DbNewInstanceExpression; if (null == projection) { throw EntityUtil.NotSupported(System.Data.Entity.Strings.Update_UnsupportedProjection(node.Projection.ExpressionKind)); } // Initialize empty structure containing space for every element of the projection. PropagatorResult[] projectedValues = new PropagatorResult[projection.Arguments.Count]; // Extract value from the input row for every projection argument requested. for (int ordinal = 0; ordinal < projectedValues.Length; ordinal++) { projectedValues[ordinal] = Evaluator.Evaluate(projection.Arguments[ordinal], row, this); } // Return a new row containing projected values. PropagatorResult projectedRow = PropagatorResult.CreateStructuralValue(projectedValues, (StructuralType)resultType.EdmType, false); return(projectedRow); }
/// <summary> /// Given default values for children members, produces a new default expression for the requested (parent) member. /// </summary> /// <param name="node">Parent member</param> /// <returns>Default value for parent member</returns> internal PropagatorResult Visit(EdmMember node) { PropagatorResult result; TypeUsage nodeType = Helper.GetModelTypeUsage(node); if (Helper.IsScalarType(nodeType.EdmType)) { GetPropagatorResultForPrimitiveType(Helper.AsPrimitive(nodeType.EdmType), out result); } else { // Construct a new 'complex type' (really any structural type) member. StructuralType structuralType = (StructuralType)nodeType.EdmType; IBaseList <EdmMember> members = TypeHelpers.GetAllStructuralMembers(structuralType); PropagatorResult[] args = new PropagatorResult[members.Count]; for (int ordinal = 0; ordinal < members.Count; ordinal++) // foreach (EdmMember member in members) { args[ordinal] = Visit(members[ordinal]); } result = PropagatorResult.CreateStructuralValue(args, structuralType, false); } return(result); }
/// <summary> /// Specialization of <see cref="CreatePlaceholder" /> for a relationship set extent. /// </summary> /// <param name="associationSet"></param> /// <returns></returns> private PropagatorResult CreateAssociationSetPlaceholder(AssociationSet associationSet) { Debug.Assert(null != associationSet, "Caller must verify parameters are not null"); var endMetadata = associationSet.ElementType.AssociationEndMembers; PropagatorResult[] endReferenceValues = new PropagatorResult[endMetadata.Count]; // Create a reference expression for each end in the relationship for (int endOrdinal = 0; endOrdinal < endMetadata.Count; endOrdinal++) { var end = endMetadata[endOrdinal]; EntityType entityType = (EntityType)((RefType)end.TypeUsage.EdmType).ElementType; // Retrieve key values for this end PropagatorResult[] keyValues = new PropagatorResult[entityType.KeyMembers.Count]; for (int memberOrdinal = 0; memberOrdinal < entityType.KeyMembers.Count; memberOrdinal++) { EdmMember keyMember = entityType.KeyMembers[memberOrdinal]; PropagatorResult keyValue = CreateMemberPlaceholder(keyMember); keyValues[memberOrdinal] = keyValue; } RowType endType = entityType.GetKeyRowType(m_parent.MetadataWorkspace); PropagatorResult refKeys = PropagatorResult.CreateStructuralValue(keyValues, endType, false); endReferenceValues[endOrdinal] = refKeys; } PropagatorResult result = PropagatorResult.CreateStructuralValue(endReferenceValues, associationSet.ElementType, false); return(result); }
// Note that this is called only for association ends. Entities have key values inline. private PropagatorResult CreateEntityKeyResult(IEntityStateEntry stateEntry, EntityKey entityKey) { // get metadata for key EntityType entityType = entityKey.GetEntitySet(m_translator.MetadataWorkspace).ElementType; RowType keyRowType = entityType.GetKeyRowType(m_translator.MetadataWorkspace); ExtractorMetadata keyMetadata = m_translator.GetExtractorMetadata(stateEntry.EntitySet, keyRowType); int keyMemberCount = keyRowType.Properties.Count; PropagatorResult[] keyValues = new PropagatorResult[keyMemberCount]; for (int ordinal = 0; ordinal < keyRowType.Properties.Count; ordinal++) { EdmMember keyMember = keyRowType.Properties[ordinal]; // retrieve information about this key value MemberInformation keyMemberInformation = keyMetadata.m_memberMap[ordinal]; int keyIdentifier = m_translator.KeyManager.GetKeyIdentifierForMemberOffset(entityKey, ordinal, keyRowType.Properties.Count); object keyValue = null; if (entityKey.IsTemporary) { // If the EntityKey is temporary, we need to retrieve the appropriate // key value from the entity itself (or in this case, the IEntityStateEntry). IEntityStateEntry entityEntry = stateEntry.StateManager.GetEntityStateEntry(entityKey); Debug.Assert(entityEntry.State == EntityState.Added, "The corresponding entry for a temp EntityKey should be in the Added State."); keyValue = entityEntry.CurrentValues[keyMember.Name]; } else { // Otherwise, we extract the value from within the EntityKey. keyValue = entityKey.FindValueByName(keyMember.Name); } Debug.Assert(keyValue != null, "keyValue should've been retrieved."); // construct propagator result keyValues[ordinal] = PropagatorResult.CreateKeyValue( keyMemberInformation.Flags, keyValue, stateEntry, keyIdentifier); // see UpdateTranslator.Identifiers for information on key identifiers and ordinals } return(PropagatorResult.CreateStructuralValue(keyValues, keyMetadata.m_type, false)); }
/// <summary> /// Converts a record to a propagator result /// </summary> /// <param name="stateEntry">state manager entry containing the record</param> /// <param name="isModified">Indicates whether the root element is modified (i.e., whether the type has changed)</param> /// <param name="record">Record to convert</param> /// <param name="useCurrentValues">Indicates whether we are retrieving current or original values.</param> /// <param name="translator">Translator for session context; registers new metadata for the record type if none /// exists</param> /// <param name="modifiedPropertiesBehavior">Indicates how to determine whether a property is modified.</param> /// <returns>Result corresponding to the given record</returns> internal static PropagatorResult ExtractResultFromRecord(IEntityStateEntry stateEntry, bool isModified, IExtendedDataRecord record, bool useCurrentValues, UpdateTranslator translator, ModifiedPropertiesBehavior modifiedPropertiesBehavior) { StructuralType structuralType = (StructuralType)record.DataRecordInfo.RecordType.EdmType; ExtractorMetadata metadata = translator.GetExtractorMetadata(stateEntry.EntitySet, structuralType); EntityKey key = stateEntry.EntityKey; PropagatorResult[] nestedValues = new PropagatorResult[record.FieldCount]; for (int ordinal = 0; ordinal < nestedValues.Length; ordinal++) { nestedValues[ordinal] = metadata.RetrieveMember(stateEntry, record, useCurrentValues, key, ordinal, modifiedPropertiesBehavior); } return(PropagatorResult.CreateStructuralValue(nestedValues, structuralType, isModified)); }
/// <summary> /// Specialization of <see cref="CreatePlaceholder" /> for an entity set extent. /// </summary> /// <param name="entitySet"></param> /// <returns></returns> private PropagatorResult CreateEntitySetPlaceholder(EntitySet entitySet) { EntityUtil.CheckArgumentNull(entitySet, "entitySet"); ReadOnlyMetadataCollection <EdmProperty> members = entitySet.ElementType.Properties; PropagatorResult[] memberValues = new PropagatorResult[members.Count]; for (int ordinal = 0; ordinal < members.Count; ordinal++) { PropagatorResult memberValue = CreateMemberPlaceholder(members[ordinal]); memberValues[ordinal] = memberValue; } PropagatorResult result = PropagatorResult.CreateStructuralValue(memberValues, entitySet.ElementType, false); return(result); }
/// <summary> /// Produce a tuple containing joined rows. /// </summary> /// <param name="left">Left row.</param> /// <param name="right">Right row.</param> /// <param name="leftKey">Key used to join left element.</param> /// <param name="rightKey">Key used to join right element.</param> /// <param name="result">Result change node; used for type information.</param> /// <returns>Result of joining the input rows.</returns> private PropagatorResult CreateResultTuple(Tuple <CompositeKey, PropagatorResult> left, Tuple <CompositeKey, PropagatorResult> right, ChangeNode result) { // using ref compare to avoid triggering value based CompositeKey leftKey = left.Item1; CompositeKey rightKey = right.Item1; Dictionary <PropagatorResult, PropagatorResult> map = null; if (!object.ReferenceEquals(null, leftKey) && !object.ReferenceEquals(null, rightKey) && !object.ReferenceEquals(leftKey, rightKey)) { // Merge key values from the left and the right (since they're equal, there's a possibility we'll // project values only from the left or the right hand side and lose important context.) CompositeKey mergedKey = leftKey.Merge(m_parent.m_updateTranslator.KeyManager, rightKey); // create a dictionary so that we can replace key values with merged key values (carrying context // from both sides) map = new Dictionary <PropagatorResult, PropagatorResult>(); for (int i = 0; i < leftKey.KeyComponents.Length; i++) { map[leftKey.KeyComponents[i]] = mergedKey.KeyComponents[i]; map[rightKey.KeyComponents[i]] = mergedKey.KeyComponents[i]; } } PropagatorResult[] joinRecordValues = new PropagatorResult[2]; joinRecordValues[0] = left.Item2; joinRecordValues[1] = right.Item2; PropagatorResult join = PropagatorResult.CreateStructuralValue(joinRecordValues, (StructuralType)result.ElementType.EdmType, false); // replace with merged key values as appropriate if (null != map) { PropagatorResult replacement; join = join.Replace(original => map.TryGetValue(original, out replacement) ? replacement : original); } return(join); }