private FunctionParameter CreateFunctionImportParameter(FunctionParameter storeParameter, UniqueIdentifierService usedParameterNames) { Debug.Assert(storeParameter.Mode == ParameterMode.In, "Function import mapping is supported only for 'In' parameters."); string name = CreateModelName(storeParameter.Name, usedParameterNames); TypeUsage cspaceTypeUsage = storeParameter.TypeUsage.GetModelTypeUsage(); var modelParameter = new FunctionParameter(name, cspaceTypeUsage, storeParameter.Mode); return modelParameter; }
private ComplexType CreateModelComplexTypeForTvfResult(LoadMethodSessionState session, string functionImportName, RowType tvfReturnType) { Debug.Assert(MetadataUtil.IsStoreType(tvfReturnType), "this is not a store type"); // create all the properties List<EdmMember> members = new List<EdmMember>(); UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false); string name = CreateModelName(functionImportName + "_Result", session.UsedGlobalModelTypeNames); // Don't want to have a property with the same name as the complex type usedPropertyNames.RegisterUsedIdentifier(name); foreach (EdmProperty storeProperty in tvfReturnType.Properties) { EdmProperty property = CreateModelProperty(session, storeProperty, usedPropertyNames); members.Add(property); } var complexType = new ComplexType(name, _namespaceName, DataSpace.CSpace); foreach (var m in members) { complexType.AddMember(m); } return complexType; }
private string CreateModelName(string storeName, UniqueIdentifierService usedNames) { string newName = CreateModelName(storeName); newName = usedNames.AdjustIdentifier(newName); return newName; }
private void MapFunctions(LoadMethodSessionState session, EntityContainer modelEntityContainer) { if (_storeFunctions == null || _storeFunctions.Length == 0 || _targetEntityFrameworkVersion < EntityFrameworkVersions.Version3) { return; } // // Create function imports and appropriate complex types for return parameters and add them to the item collection (session.EdmItemCollection). // Create and add function mappings. // var interestingStoreFunctions = _storeFunctions.Where( f => f.IsComposableAttribute && !f.AggregateAttribute && f.Parameters.All(p => p.Mode == ParameterMode.In)); foreach (var storeFunction in interestingStoreFunctions) { RowType tvfReturnType = TypeHelpers.GetTvfReturnType(storeFunction); if (tvfReturnType == null) { continue; } // Create function import name. string functionImportName = CreateModelName(storeFunction.Name, session.UsedEntityContainerItemNames); // Create function import parameters. UniqueIdentifierService usedParameterNames = new UniqueIdentifierService(false); var parameters = storeFunction.Parameters.Select(p => CreateFunctionImportParameter(p, usedParameterNames)).ToArray(); var failedStoreParameterName = storeFunction.Parameters.Select(p => p.Name).Except(parameters.Select(p => p.Name)).FirstOrDefault(); if (failedStoreParameterName != null) { session.AddError(Strings.UnableToGenerateFunctionImportParameterName(failedStoreParameterName, storeFunction.Identity), ModelBuilderErrorCode.UnableToGenerateFunctionImportParameterName, EdmSchemaErrorSeverity.Warning, null); continue; } // Create new complex type and register it in the item collection. var complexType = CreateModelComplexTypeForTvfResult(session, functionImportName, tvfReturnType); complexType.SetReadOnly(); session.EdmItemCollection.AddInternal(complexType); var collectionType = complexType.GetCollectionType(); collectionType.SetReadOnly(); var returnTypeUsage = TypeUsage.Create(collectionType); // Create function import and register it in the item collection. var functionImport = new EdmFunction(functionImportName, _modelEntityContainerName, DataSpace.CSpace, new EdmFunctionPayload() { Name = functionImportName, NamespaceName = _namespaceName, ReturnParameters = new FunctionParameter[] {new FunctionParameter(EdmConstants.ReturnType, returnTypeUsage, ParameterMode.ReturnValue)}, Parameters = parameters, DataSpace = DataSpace.CSpace, IsComposable = true, IsFunctionImport = true }); functionImport.SetReadOnly(); modelEntityContainer.AddFunctionImport(functionImport); // Add mapping tuple. session.MappingLookups.StoreFunctionToFunctionImport.Add(Tuple.Create(storeFunction, functionImport)); } }
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); } }
private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames, RelationshipMultiplicity multiplicityOverride, OperationAction deleteBehaviorOverride) { Debug.Assert(storeEndMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "The type is not a ref type"); Debug.Assert(((RefType)storeEndMember.TypeUsage.EdmType).ElementType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "the ref is not holding on to an EntityType"); EntityType storeEntityType = ((EntityType)((RefType)storeEndMember.TypeUsage.EdmType).ElementType); EntityType modelEntityType = session.MappingLookups.StoreEntityTypeToModelEntityType[storeEntityType]; string name = CreateModelName(storeEndMember.Name, usedEndMemberNames); AssociationEndMember end = new AssociationEndMember(name, modelEntityType.GetReferenceType(), multiplicityOverride); end.DeleteBehavior = deleteBehaviorOverride; return end; }
private void CreateModelNavigationProperty(LoadMethodSessionState session, AssociationEndMember from, AssociationEndMember to) { EntityType entityType = (EntityType)((RefType)from.TypeUsage.EdmType).ElementType; UniqueIdentifierService usedMemberNames = new UniqueIdentifierService(false); LoadNameLookupWithUsedMemberNames(entityType, usedMemberNames); string name = CreateModelName(this._pluralizationServiceHandler.GetNavigationPropertyName(to, to.Name), usedMemberNames); NavigationProperty navigationProperty = new NavigationProperty(name, to.TypeUsage); navigationProperty.RelationshipType = (AssociationType)to.DeclaringType; navigationProperty.ToEndMember = to; navigationProperty.FromEndMember = from; entityType.AddMember(navigationProperty); }
private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsedAssociationSet) { // create the association string associationName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedGlobalModelTypeNames); AssociationType association = new AssociationType(associationName, _namespaceName, false, DataSpace.CSpace); // create the association set string associationSetName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedEntityContainerItemNames); AssociationSet set = new AssociationSet(associationSetName, association); // create the association and association set end members UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false); for(int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++) { AssociationSetEnd storeEnd; RelationshipMultiplicity multiplicity; OperationAction deleteBehavior; collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior); AssociationEndMember end = CreateAssociationEndMember(session, storeEnd.CorrespondingAssociationEndMember, usedEndMemberNames, multiplicity, deleteBehavior); association.AddMember(end); EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet]; AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end); set.AddAssociationSetEnd(setEnd); session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, setEnd); } // don't need a referential constraint CreateModelNavigationProperties(session, association); collapsedAssociationSet.ModelAssociationSet = set; return set; }
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 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); }
/// <summary> /// Create a method entry point for a function import yielding an entity reader. /// </summary> /// <param name="functionImport">SOM for function import; must not be null and must yield /// an entity reader.</param> /// <returns>Method definition.</returns> private CodeMemberMethod CreateFunctionImportStructuralTypeReaderMethod(EdmFunction functionImport) { // Trying to get: // ///// <summary> ///// Documentation ///// </summary> //public ObjectQueryResult<MyType> MyFunctionImport(Nullable<int> id, string foo) //{ // ObjectParameter idParameter; // if (id.HasValue) // { // idParameter = new ObjectParameter("id", id); // } // else // { // idParameter = new ObjectParameter("id", typeof(int)); // } // ObjectParameter fooParameter; // if (null != foo) // { // fooParameter = new ObjectParameter("foo", foo); // } // else // { // fooParameter = new ObjectParameter("foo", typeof(string)); // } // return base.ExecuteFunction<MyType>("MyFunctionImport", idParameter, fooParameter); //} Debug.Assert(null != functionImport); CodeMemberMethod method = new CodeMemberMethod(); Generator.AttributeEmitter.EmitGeneratedCodeAttribute(method); method.Name = functionImport.Name; method.Attributes = GetFunctionImportAccessibility(functionImport) | MemberAttributes.Final; UniqueIdentifierService uniqueIdentifierService = new UniqueIdentifierService( this.Generator.IsLanguageCaseSensitive, s => Utils.FixParameterName(s)); // determine element return type EdmType returnType = GetReturnTypeFromFunctionImport(functionImport); if (Helper.IsCollectionType(returnType)) { // get the type in the collection returnType = ((CollectionType)returnType).TypeUsage.EdmType; } CodeTypeReference elementType = Generator.GetLeastPossibleQualifiedTypeReference(returnType); method.ReturnType = TypeReference.ObjectResult(elementType); // generate <summary> comments based on CSDL Documentation element CommentEmitter.EmitSummaryComments(functionImport, method.Comments); // build up list of arguments to ExecuteFunction List<CodeExpression> executeArguments = new List<CodeExpression>(); executeArguments.Add(new CodePrimitiveExpression(functionImport.Name)); // first argument is the name of the function foreach (FunctionParameter parameter in functionImport.Parameters) { CreateFunctionArgument(method, uniqueIdentifierService, parameter); } // add fields representing object parameters foreach (FunctionParameter parameter in functionImport.Parameters) { if (parameter.Mode == ParameterMode.In) { CodeExpression variableReference = CreateFunctionParameter(method, uniqueIdentifierService, parameter); executeArguments.Add(variableReference); } else { // the parameter is already being passed in as an argument; just remember it and // pass it in as an argument string adjustedParameterName; if (!uniqueIdentifierService.TryGetAdjustedName(parameter, out adjustedParameterName)) { Debug.Fail("parameter must be registered in identifier service"); } executeArguments.Add(new CodeVariableReferenceExpression(adjustedParameterName)); } } // Add call to ExecuteFunction // return ExecuteFunction<elementType>("FunctionImportName", { object parameters }); CodeMethodReferenceExpression executeFunctionMethod = new CodeMethodReferenceExpression( new CodeBaseReferenceExpression(), "ExecuteFunction", new CodeTypeReference[] { elementType }); method.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression(executeFunctionMethod, executeArguments.ToArray()) ) ); // invoke the ExecuteFunction method passing in parameters return method; }
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 CreateAssociationType(LoadMethodSessionState session, List<RelationshipDetailsRow> columns) { Debug.Assert(columns.Count != 0, "should have at least one column"); RelationshipDetailsRow firstRow = columns[0]; // get the entity types for the ends EntityType pkEntityType; EntityType fkEntityType; if (!TryGetEndEntities(session, firstRow, out pkEntityType, out fkEntityType)) { return; } if (!AreRelationshipColumnsTheTypesEntireKey(pkEntityType, columns, r => r.PKColumn)) { session.AddErrorsForType(pkEntityType, new EdmSchemaError(Strings.UnsupportedDbRelationship(firstRow.RelationshipName), (int)ModelBuilderErrorCode.UnsupportedDbRelationship, EdmSchemaErrorSeverity.Warning)); return; } UniqueIdentifierService usedEndNames = new UniqueIdentifierService(false); // figure out the lower bound of the pk end bool someFkColmnsAreNullable; if (_targetEntityFrameworkVersion == EntityFrameworkVersions.Version1) { someFkColmnsAreNullable = AreAllFkKeyColumnsNullable(fkEntityType, columns); } else { someFkColmnsAreNullable = AreAnyFkKeyColumnsNullable(fkEntityType, columns); } RelationshipMultiplicity pkMultiplicity = someFkColmnsAreNullable ? RelationshipMultiplicity.ZeroOrOne : RelationshipMultiplicity.One; //Get the Delete Action for the end and set it. //The only DeleteAction we support is Cascade, ignor all others for now. OperationAction onDeleteAction = OperationAction.None; if (firstRow.RelationshipIsCascadeDelete) { onDeleteAction = OperationAction.Cascade; } AssociationEndMember pkEnd = CreateAssociationEnd( session, pkEntityType, pkMultiplicity, usedEndNames, onDeleteAction); RelationshipMultiplicity fkMultiplicity = RelationshipMultiplicity.Many; if ( !someFkColmnsAreNullable && AreRelationshipColumnsTheTypesEntireKey(fkEntityType, columns, r => r.FKColumn)) { // both the pk and fk side columns are the keys of their types // so this is a 1 to one relationship fkMultiplicity = RelationshipMultiplicity.ZeroOrOne; } AssociationEndMember fkEnd = CreateAssociationEnd(session, fkEntityType, fkMultiplicity, usedEndNames, OperationAction.None); // create the type string typeName = session.UsedTypeNames.AdjustIdentifier(firstRow.RelationshipName); AssociationType type = new AssociationType(typeName, _namespaceName, false, DataSpace.SSpace); type.AddMember(pkEnd); type.AddMember(fkEnd); List<EdmSchemaError> errors = new List<EdmSchemaError>(); bool isValid = CreateReferentialConstraint(session, type, pkEnd, fkEnd, columns, errors); string errorMessage; // We can skip most validation checks if the FKs are directly surfaced (since we can produce valid mappings in these cases). if (!this.GenerateForeignKeyProperties) { if (IsFkPartiallyContainedInPK(type, out errorMessage)) { errors.Add(new EdmSchemaError( errorMessage, (int)ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Warning)); isValid = false; } if (isValid) { //Now check if any FK (which could also be a PK) is shared among multiple Associations (ie shared via foreign key constraint). // To do this we check if the Association Type being generated has any dependent property which is also a dependent in one of the association typed already added. //If so, we keep one Association and throw the rest away. foreach (var toPropertyOfAddedAssociation in session.AssociationTypes.SelectMany(t => t.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties))) { foreach (var toProperty in type.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties)) { if (toProperty.DeclaringType.Equals(toPropertyOfAddedAssociation.DeclaringType) && toProperty.Equals(toPropertyOfAddedAssociation)) { errors.Add(new EdmSchemaError( Strings.SharedForeignKey(type.Name, toProperty, toProperty.DeclaringType), (int)ModelBuilderErrorCode.SharedForeignKey, EdmSchemaErrorSeverity.Warning)); isValid = false; break; } } if (!isValid) { break; } } } } if (isValid) { session.AssociationTypes.Add(type); } else { session.InvalidTypes.Add(type); session.RelationshipEndTypeLookup.Remove(pkEnd); session.RelationshipEndTypeLookup.Remove(fkEnd); } type.SetReadOnly(); session.AddErrorsForType(type, errors); }
private EntityType CreateModelEntityType(LoadMethodSessionState session, EntityType storeEntityType) { Debug.Assert(MetadataUtil.IsStoreType(storeEntityType), "this is not a store type"); Debug.Assert(storeEntityType.BaseType == null, "we are assuming simple generation from a database where no types will have a base type"); EntityType foundEntity; if (session.MappingLookups.StoreEntityTypeToModelEntityType.TryGetValue(storeEntityType, out foundEntity)) { // this entity type is used in two different entity sets return foundEntity; } // create all the properties List<EdmMember> members = new List<EdmMember>(); List<String> keyMemberNames = new List<string>(); UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false); string name = CreateModelName(this._pluralizationServiceHandler.GetEntityTypeName(storeEntityType.Name), session.UsedGlobalModelTypeNames); // Don't want to have a property with the same name as the entity type usedPropertyNames.RegisterUsedIdentifier(name); foreach (EdmProperty storeProperty in storeEntityType.Properties) { // add fk properties only if requested EdmMember member; bool isKey = storeEntityType.KeyMembers.TryGetValue(storeProperty.Name, false, out member); AssociationType association; if (isKey || this.GenerateForeignKeyProperties || !session.FkProperties.TryGetValue(storeProperty, out association)) { EdmProperty property = CreateModelProperty(session, storeProperty, usedPropertyNames); members.Add(property); if (isKey) { keyMemberNames.Add(property.Name); } } } var entityType = new EntityType(name, _namespaceName, DataSpace.CSpace, keyMemberNames, members); session.MappingLookups.StoreEntityTypeToModelEntityType.Add(storeEntityType, entityType); return entityType; }
private void LoadNameLookupWithUsedMemberNames(EntityType entityType, UniqueIdentifierService usedMemberNames) { // a property should not have the same name as its entity usedMemberNames.RegisterUsedIdentifier(entityType.Name); foreach (EdmMember member in entityType.Members) { usedMemberNames.RegisterUsedIdentifier(member.Name); } }
private EdmProperty CreateModelProperty(LoadMethodSessionState session, EdmProperty storeProperty, UniqueIdentifierService usedPropertyNames) { string name = CreateModelName(storeProperty.Name, usedPropertyNames); TypeUsage cspaceTypeUsage = storeProperty.TypeUsage.GetModelTypeUsage(); EdmProperty property = new EdmProperty(name, cspaceTypeUsage); this.AddStoreGeneratedPatternAnnoation(property, storeProperty.TypeUsage); session.MappingLookups.StoreEdmPropertyToModelEdmProperty.Add(storeProperty, property); return property; }
private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, KeyValuePair<string, RelationshipMultiplicity> endMultiplicityOverride, UniqueIdentifierService usedEndMemberNames) { RelationshipMultiplicity multiplicity = storeEndMember.RelationshipMultiplicity; if (endMultiplicityOverride.Key != null && endMultiplicityOverride.Key == storeEndMember.Name) { multiplicity = endMultiplicityOverride.Value; } return CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames, multiplicity, storeEndMember.DeleteBehavior); }
private AssociationType CreateModelAssociationType(LoadMethodSessionState session, AssociationType storeAssociationType) { UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false); string name = CreateModelName(storeAssociationType.Name, session.UsedGlobalModelTypeNames); bool isFkAssociation = false; if (_targetEntityFrameworkVersion > EntityFrameworkVersions.Version1) { isFkAssociation = this.GenerateForeignKeyProperties || RequiresModelReferentialConstraint(storeAssociationType); } AssociationType association = new AssociationType(name, _namespaceName, isFkAssociation, DataSpace.CSpace); KeyValuePair<string, RelationshipMultiplicity> endMultiplicityOverride = CreateEndMultiplicityOverride(session, storeAssociationType, association); foreach (AssociationEndMember storeEndMember in storeAssociationType.RelationshipEndMembers) { AssociationEndMember end = CreateAssociationEndMember(session, storeEndMember, endMultiplicityOverride, usedEndMemberNames); session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember.Add(storeEndMember, end); association.AddMember(end); } ReferentialConstraint constraint = CreateReferentialConstraint(session, storeAssociationType); if (constraint != null) { association.AddReferentialConstraint(constraint); } CreateModelNavigationProperties(session, association); return association; }
/// <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); }