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);
        }