private string CreateModelName(string storeName, UniqueIdentifierService usedNames) { string newName = CreateModelName(storeName); newName = usedNames.AdjustIdentifier(newName); return newName; }
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); }
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); }