private string CreateModelName(string storeName, UniqueIdentifierService usedNames)
 {
     string newName = CreateModelName(storeName);
     newName = usedNames.AdjustIdentifier(newName);
     return newName;            
 }
Ejemplo n.º 2
0
        private void CreateFunctionArgument(CodeMemberMethod method, UniqueIdentifierService uniqueIdentifierService, FunctionParameter parameter)
        {
            // get type of parameter
            Type clrType = DetermineParameterType(parameter);

            // parameters to stored procedures must be nullable
            CodeTypeReference argumentType = clrType.IsValueType ? TypeReference.NullableForType(clrType) : TypeReference.ForType(clrType);
            string parameterName = uniqueIdentifierService.AdjustIdentifier(parameter.Name, parameter);
            CodeParameterDeclarationExpression codeParameter = new CodeParameterDeclarationExpression(argumentType, parameterName);
            method.Parameters.Add(codeParameter);
        }
Ejemplo n.º 3
0
        private CodeExpression CreateFunctionParameter(CodeMemberMethod method, UniqueIdentifierService uniqueIdentifierService, FunctionParameter parameter)
        {
            // get (adjusted) name of parameter
            string adjustedParameterName;
            if (!uniqueIdentifierService.TryGetAdjustedName(parameter, out adjustedParameterName))
            {
                Debug.Fail("parameter must be registered in identifier service");
            }
            Type parameterType = DetermineParameterType(parameter);

            // make sure the variable name does not collide with any parameters to the method, or any
            // existing variables (all registered in the service)
            string variableName = uniqueIdentifierService.AdjustIdentifier(parameter.Name + "Parameter");

            // ObjectParameter variableName;
            // if (null != parameterName)
            // {
            //     variableName = new ObjectParameter("parameterName", adjustedParameterName);
            // }
            // else
            // {
            //     variableName = new ObjectParameter("parameterName", typeof(parameterType));
            // }
            method.Statements.Add(
                new CodeVariableDeclarationStatement(TypeReference.ForType(typeof(ObjectParameter)), variableName));
            CodeExpression variableReference = new CodeVariableReferenceExpression(variableName);
            CodeExpression parameterReference = new CodeVariableReferenceExpression(adjustedParameterName);
            CodeStatement nullConstructor = new CodeAssignStatement(variableReference,
                new CodeObjectCreateExpression(TypeReference.ForType(typeof(ObjectParameter)),
                new CodePrimitiveExpression(parameter.Name),
                new CodeTypeOfExpression(TypeReference.ForType(parameterType))));
            CodeStatement valueConstructor = new CodeAssignStatement(variableReference,
                new CodeObjectCreateExpression(TypeReference.ForType(typeof(ObjectParameter)),
                new CodePrimitiveExpression(parameter.Name),
                parameterReference));
            CodeExpression notNullCondition;
            if (parameterType.IsValueType)
            {
                // Value type parameters generate Nullable<ValueType> arguments (see CreateFunctionArgument).
                // We call Nullable<ValueType>.HasValue to determine whether the argument passed in is null
                // (since null != nullableTypeInstance does not work in VB)
                //
                // parameterReference.HasValue
                notNullCondition = new CodePropertyReferenceExpression(
                    parameterReference,
                    "HasValue");
            }
            else
            {
                // use parameterReference != null
                notNullCondition = new CodeBinaryOperatorExpression(
                    parameterReference,
                    CodeBinaryOperatorType.IdentityInequality,
                    NullExpression);
            }
            method.Statements.Add(
                new CodeConditionStatement(
                    notNullCondition,
                    new CodeStatement[] { valueConstructor, },
                    new CodeStatement[] { nullConstructor, }
                )
            );
            return variableReference;
        }
 private AssociationEndMember CreateAssociationEnd(LoadMethodSessionState session, 
     EntityType type, 
     RelationshipMultiplicity multiplicity,
     UniqueIdentifierService usedEndNames,
     OperationAction deleteAction
     )
 {
     string role = usedEndNames.AdjustIdentifier(type.Name);
     RefType refType = type.GetReferenceType();
     AssociationEndMember end = new AssociationEndMember(role, refType, multiplicity);
     end.DeleteBehavior = deleteAction;
     session.RelationshipEndTypeLookup.Add(end, type);
     return end;
 }
        private void CreateEdmFunction(LoadMethodSessionState session, DbObjectKey functionKey, List<FunctionDetailsReader.Memento> parameters)
        {
            Debug.Assert(parameters.Count != 0, "don't call the method with no data");

            FunctionDetailsReader row = parameters[0].CreateReader();

            FunctionParameter returnParameter = null;
            bool isValid = true;
            List<EdmSchemaError> errors = new List<EdmSchemaError>();
            if (row.ReturnType != null)
            {
                Debug.Assert(!row.IsTvf, "TVF can't have ReturnType (used only for scalars).");
                bool excludedForTarget;
                TypeUsage returnType = GetScalarFunctionTypeUsage(session, row.ReturnType, out excludedForTarget);
                if (returnType != null)
                {
                    returnParameter = new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue);
                }
                else
                {
                    isValid = false;
                    errors.Add(new EdmSchemaError(excludedForTarget ?
                                                  Strings.UnsupportedFunctionReturnDataTypeForTarget(row.ProcedureName, row.ReturnType) :
                                                  Strings.UnsupportedFunctionReturnDataType(row.ProcedureName, row.ReturnType),
                                                  (int)ModelBuilderErrorCode.UnsupportedType,
                                                  EdmSchemaErrorSeverity.Warning));
                }
            }
            else if (row.IsTvf)
            {
                if (_targetEntityFrameworkVersion < EntityFrameworkVersions.Version3)
                {
                    return;
                }
                RowType tvfReturnType;
                if (session.TryGetTvfReturnType(functionKey, out tvfReturnType) && !session.InvalidTypes.Contains(tvfReturnType))
                {
                    var collectionType = tvfReturnType.GetCollectionType();
                    collectionType.SetReadOnly();
                    returnParameter = new FunctionParameter(EdmConstants.ReturnType, TypeUsage.Create(collectionType), ParameterMode.ReturnValue);
                }
                else
                {
                    isValid = false;

                    // If the TVF return type exists, but it is not valid, then reassign all its errors directly to the TVF.
                    // This is needed in order to avoid the following kind of error reporting:
                    // SSDL:
                    // 
                    // <!-- Errors found while generating type:
                    //    column1 type not supported
                    //    column2 type not supported
                    //   <RowType />
                    // -->
                    // ...
                    // ...
                    // <!-- Error found while generating type:
                    //    TableReferencedByTvfWasNotFound
                    //   <Function Name="TVF" .... />
                    // -->
                    // 
                    // Instead we want something like this:
                    // 
                    // <!-- Errors found while generating type:
                    //    column1 type not supported
                    //    column2 type not supported
                    //    TableReferencedByTvfWasNotFound
                    //   <Function Name="TVF" .... />
                    // -->
                    // 

                    List<EdmSchemaError> tvfReturnTypeErrors;
                    if (tvfReturnType != null && session.ItemToErrorsMap.TryGetValue(tvfReturnType, out tvfReturnTypeErrors))
                    {
                        errors.AddRange(tvfReturnTypeErrors);
                        session.ItemToErrorsMap.Remove(tvfReturnType);
                        if (session.InvalidTypes.Contains(tvfReturnType))
                        {
                            session.InvalidTypes.Remove(tvfReturnType);
                        }
                    }
                    
                    errors.Add(new EdmSchemaError(
                        Strings.TableReferencedByTvfWasNotFound(functionKey),
                        (int)ModelBuilderErrorCode.MissingTvfReturnTable,
                        EdmSchemaErrorSeverity.Warning));
                }
            }
            
            bool caseSensitive = false;
            UniqueIdentifierService uniqueIdentifiers = new UniqueIdentifierService(caseSensitive);
            List<FunctionParameter> functionParameters = new List<FunctionParameter>();
            for (int i = 0; i < parameters.Count && !row.IsParameterNameNull; i++)
            {
                row.Attach(parameters[i]);
                TypeUsage parameterType = null;
                bool excludedForTarget = false;
                if (!row.IsParameterTypeNull)
                {
                    parameterType = GetScalarFunctionTypeUsage(session, row.ParameterType, out excludedForTarget);
                }

                if (parameterType != null)
                {
                    ParameterMode mode;
                    if (!row.TryGetParameterMode(out mode))
                    {
                        isValid = false;
                        string modeValue = "null";
                        if (!row.IsParameterModeNull)
                        {
                            modeValue = row.ProcParameterMode;
                        }
                        errors.Add(new EdmSchemaError(
                            Strings.ParameterDirectionNotValid(
                            row.ProcedureName,
                            row.ParameterName,
                            modeValue),
                            (int)ModelBuilderErrorCode.ParameterDirectionNotValid,
                            EdmSchemaErrorSeverity.Warning));
                    }

                    // the mode will get defaulted to something, so it is ok to keep creating after
                    // an error getting the mode value.
                    string parameterName = EntityModelSchemaGenerator.CreateValidEcmaName(row.ParameterName, 'p');
                    parameterName = uniqueIdentifiers.AdjustIdentifier(parameterName);
                    FunctionParameter parameter = new FunctionParameter(parameterName, parameterType, mode);
                    functionParameters.Add(parameter);
                }
                else
                {
                    isValid = false;
                    string typeValue = "null";
                    if (!row.IsParameterTypeNull)
                    {
                        typeValue = row.ParameterType;
                    }
                    errors.Add(new EdmSchemaError(excludedForTarget ?
                                                  Strings.UnsupportedFunctionParameterDataTypeForTarget(row.ProcedureName, row.ParameterName, i, typeValue) :
                                                  Strings.UnsupportedFunctionParameterDataType(row.ProcedureName, row.ParameterName, i, typeValue),
                                                  (int)ModelBuilderErrorCode.UnsupportedType,
                                                  EdmSchemaErrorSeverity.Warning));
                }
            }

            string functionName = EntityModelSchemaGenerator.CreateValidEcmaName(row.ProcedureName, 'f');
            functionName = session.UsedTypeNames.AdjustIdentifier(functionName);
            FunctionParameter[] returnParameters = 
                returnParameter == null ? new FunctionParameter[0] : new FunctionParameter[] {returnParameter};
            EdmFunction function = new EdmFunction(functionName,
                _namespaceName,
                DataSpace.SSpace,
                new EdmFunctionPayload
                {
                    Schema = row.Schema,
                    StoreFunctionName = functionName != row.ProcedureName ? row.ProcedureName : null,
                    IsAggregate = row.IsIsAggregate,
                    IsBuiltIn = row.IsBuiltIn,
                    IsNiladic = row.IsNiladic,
                    IsComposable = row.IsComposable,
                    ReturnParameters = returnParameters,
                    Parameters = functionParameters.ToArray()
                });
            function.SetReadOnly();

            session.AddErrorsForType(function, errors);
            if (isValid)
            {
                session.Functions.Add(function);
            }
            else
            {
                session.InvalidTypes.Add(function);
            }
        }
        /// <summary>
        /// Emit static factory method which creates an instance of the class and initializes
        /// non-nullable properties (taken as arguments)
        /// </summary>
        /// <param name="typeDecl"></param>
        protected virtual void EmitFactoryMethod(CodeTypeDeclaration typeDecl)
        {
            
            
            // build list of non-nullable properties
            ReadOnlyMetadataCollection<EdmProperty> properties = GetProperties();
            List<EdmProperty> parameters = new List<EdmProperty>(properties.Count);
            foreach (EdmProperty property in properties)
            {
                bool include = IncludeFieldInFactoryMethod(property);
                if (include)
                {
                    parameters.Add(property);
                }
            }

            // if there are no parameters, we don't emit anything (1 is for the null element)
            // nor do we emit everything if this is the Ref propertied ctor and the parameter list is the same as the many parametered ctor
            if (parameters.Count < 1)
            {
                return;
            }

            CodeMemberMethod method = new CodeMemberMethod();
            Generator.AttributeEmitter.EmitGeneratedCodeAttribute(method);

            CodeTypeReference typeRef = TypeReference.FromString(Item.Name);
            UniqueIdentifierService uniqueIdentifierService = new UniqueIdentifierService(Generator.IsLanguageCaseSensitive, name => Utils.FixParameterName(name));
            string instanceName = uniqueIdentifierService.AdjustIdentifier(Item.Name);

            // public static Class CreateClass(...)
            method.Attributes = MemberAttributes.Static|MemberAttributes.Public;
            method.Name = "Create" + Item.Name;
            if (NavigationPropertyEmitter.IsNameAlreadyAMemberName(Item, method.Name, Generator.LanguageAppropriateStringComparer))
            {
                Generator.AddError(Strings.GeneratedFactoryMethodNameConflict(method.Name, Item.Name),
                    ModelBuilderErrorCode.GeneratedFactoryMethodNameConflict,
                    EdmSchemaErrorSeverity.Error, Item.FullName);
            }

            method.ReturnType = typeRef;
            
            // output method summary comments 
            CommentEmitter.EmitSummaryComments(Strings.FactoryMethodSummaryComment(Item.Name), method.Comments);


            // Class class = new Class();
            CodeVariableDeclarationStatement createNewInstance = new CodeVariableDeclarationStatement(
                typeRef, instanceName, new CodeObjectCreateExpression(typeRef));
            method.Statements.Add(createNewInstance);
            CodeVariableReferenceExpression instanceRef = new CodeVariableReferenceExpression(instanceName);

            // iterate over the properties figuring out which need included in the factory method
            foreach (EdmProperty property in parameters)
            {
                // CreateClass( ... , propType propName ...)
                PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, UsingStandardBaseClass);
                CodeTypeReference propertyTypeReference = propertyEmitter.PropertyType;
                String parameterName = uniqueIdentifierService.AdjustIdentifier(propertyEmitter.PropertyName);
                CodeParameterDeclarationExpression paramDecl = new CodeParameterDeclarationExpression(
                    propertyTypeReference, parameterName);
                CodeArgumentReferenceExpression paramRef = new CodeArgumentReferenceExpression(paramDecl.Name);
                method.Parameters.Add(paramDecl);

                // add comment describing the parameter
                CommentEmitter.EmitParamComments(paramDecl, Strings.FactoryParamCommentGeneral(propertyEmitter.PropertyName), method.Comments);

                CodeExpression newPropertyValue;
                if (MetadataUtil.IsComplexType(propertyEmitter.Item.TypeUsage.EdmType))
                {
                    List<CodeExpression> complexVerifyParameters = new List<CodeExpression>();
                    complexVerifyParameters.Add(paramRef);
                    complexVerifyParameters.Add(new CodePrimitiveExpression(propertyEmitter.PropertyName));
                    
                    newPropertyValue =
                        new CodeMethodInvokeExpression(
                            PropertyEmitter.CreateEdmStructuralObjectRef(TypeReference),
                            Utils.VerifyComplexObjectIsNotNullName,
                            complexVerifyParameters.ToArray());
                }
                else
                {
                    newPropertyValue = paramRef;
                }

                // Scalar property:
                //     Property = param;
                // Complex property:
                //     Property = StructuralObject.VerifyComplexObjectIsNotNull(param, propertyName);

                method.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(instanceRef, propertyEmitter.PropertyName), newPropertyValue));            
            }

            // return class;
            method.Statements.Add(new CodeMethodReturnStatement(instanceRef));

            // actually add the method to the class
            typeDecl.Members.Add(method);
        }