private EntitySet CreateEntitySet( 
            LoadMethodSessionState session,
            EntityType type 
            )
        {
            DbObjectKey key = session.GetKey(type);
            string schema = key.Schema;

            string table = null;
            if (key.TableName != type.Name)
            {
                table = key.TableName;
            }

            EntitySet entitySet = new EntitySet(type.Name, 
                        schema, 
                        table,
                        null,
                        type);

            MetadataProperty property = System.Data.EntityModel.SchemaObjectModel.SchemaElement.CreateMetadataPropertyFromOtherNamespaceXmlArtifact(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorTypeAttributeName, GetSourceNameFromObjectType(key.ObjectType));
            List<MetadataProperty> properties = new List<MetadataProperty>();
            properties.Add(property);
            entitySet.AddMetadataProperties(properties);
            entitySet.SetReadOnly();
            return entitySet;
        }
 private AssociationSetEnd CreateModelAssociationSetEnd(LoadMethodSessionState session, AssociationSetEnd storeEnd, AssociationSet parentModelAssociationSet)
 {
     AssociationEndMember associationEnd = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[storeEnd.CorrespondingAssociationEndMember];
     EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet];
     string role = associationEnd.Name;
     AssociationSetEnd end = new AssociationSetEnd(entitySet, parentModelAssociationSet, associationEnd);
     return end;
 }
        private KeyValuePair<string, RelationshipMultiplicity> CreateEndMultiplicityOverride(LoadMethodSessionState session, AssociationType storeAssociation, AssociationType modelAssociation)
        {
            // does the store have any constraints
            if (storeAssociation.ReferentialConstraints.Count == 0)
            {
                return new KeyValuePair<string, RelationshipMultiplicity>();
            }

            ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];

            //For foreign key associations, having any nullable columns will imply 0..1
            //multiplicity, while for independent associations, all columns must be non-nullable for 
            //0..1 association.
            bool nullableColumnsImplyingOneToOneMultiplicity = false;
            if (this.GenerateForeignKeyProperties)
            {
                nullableColumnsImplyingOneToOneMultiplicity = storeConstraint.ToProperties.All(p => p.Nullable == false);
            }
            else
            {
                nullableColumnsImplyingOneToOneMultiplicity = storeConstraint.ToProperties.Any(p => p.Nullable == false);
            }

            if (storeConstraint.FromRole.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne &&
               storeConstraint.ToRole.RelationshipMultiplicity == RelationshipMultiplicity.Many &&
               nullableColumnsImplyingOneToOneMultiplicity)
            {
                return new KeyValuePair<string, RelationshipMultiplicity>(storeConstraint.FromRole.Name, RelationshipMultiplicity.One);
            }

            return new KeyValuePair<string, RelationshipMultiplicity>();
        }
        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 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 bool IsAssociationPartOfCandidateCollapsedAssociation(LoadMethodSessionState session, AssociationSet storeAssociationSet)
        {
            foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds)
            {
                if (session.CandidateCollapsedAssociations.ContainsKey(end.EntitySet))
                {
                    return true;
                }
            }

            return false;
        }
 private void CollectAllFkProperties(LoadMethodSessionState session)
 {
     foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets)
     {
         if (storeSet.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
         {
             ReferentialConstraint constraint = OneToOneMappingSerializer.GetReferentialConstraint(((AssociationSet)storeSet));
             foreach (EdmProperty property in constraint.ToProperties)
             {
                 if (!session.FkProperties.ContainsKey(property))
                 {
                     session.FkProperties.Add(property, ((AssociationSet)storeSet).ElementType);
                 }
             }
         }
     }
 }
        private bool TryGetEndEntities(
            LoadMethodSessionState session,
            RelationshipDetailsRow row,
            out EntityType pkEntityType,
            out EntityType fkEntityType)
        {
            RelationshipDetailsCollection table = row.Table;
            DbObjectKey pkKey = new DbObjectKey(row[table.PKCatalogColumn],
                        row[table.PKSchemaColumn],
                        row[table.PKTableColumn], DbObjectType.Unknown);
            DbObjectKey fkKey = new DbObjectKey(row[table.FKCatalogColumn],
                        row[table.FKSchemaColumn],
                        row[table.FKTableColumn], DbObjectType.Unknown);
            
            bool worked = session.TryGetEntity(pkKey, out pkEntityType);
            worked &= session.TryGetEntity(fkKey, out fkEntityType);

            return worked;
        }
 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 CreateAssociationTypes(LoadMethodSessionState session)
        {
            string currentRelationshipId = string.Empty;
            List<RelationshipDetailsRow> columns = new List<RelationshipDetailsRow>();
            foreach (RelationshipDetailsRow row in _loader.LoadRelationships(session.Filters))
            {
                string rowRelationshipId = row.RelationshipId;
                if (rowRelationshipId != currentRelationshipId)
                {
                    if (!string.IsNullOrEmpty(currentRelationshipId))
                    {
                        CreateAssociationType(session, columns);
                        columns.Clear();
                    }
                    currentRelationshipId = rowRelationshipId;
                }

                columns.Add(row);
            }

            if (!string.IsNullOrEmpty(currentRelationshipId))
            {
                CreateAssociationType(session, columns);
            }
        }
        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 TypeUsage GetScalarFunctionTypeUsage(LoadMethodSessionState session, string dataType, out bool excludedForTarget)
 {
     PrimitiveType primitiveType;
     if (session.TryGetStorePrimitiveType(dataType, out primitiveType, out excludedForTarget))
     {
         TypeUsage usage = TypeUsage.Create(primitiveType, FacetValues.NullFacetValues);
         return usage;
     }
     return null;
 }
        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 void CreateEdmFunctions(LoadMethodSessionState session)
        {
            using(FunctionDetailsReader reader = _loader.LoadFunctionDetails(session.Filters))
            {
                DbObjectKey currentFunction = new DbObjectKey();
                List<FunctionDetailsReader.Memento> parameters = new List<FunctionDetailsReader.Memento>();
                while(reader.Read())
                {
                    DbObjectKey rowFunction = reader.CreateDbObjectKey();
                    if (rowFunction != currentFunction)
                    {
                        if (!currentFunction.IsEmpty)
                        {
                            CreateEdmFunction(session, currentFunction, parameters);
                            parameters.Clear();
                        }
                        currentFunction = rowFunction;
                    }
                    parameters.Add(reader.CreateMemento());
                }

                if (parameters.Count != 0)
                {
                    CreateEdmFunction(session, currentFunction, parameters);
                }
            }
        }
        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 bool CreateReferentialConstraint(LoadMethodSessionState session,
            AssociationType association,
            AssociationEndMember pkEnd,
            AssociationEndMember fkEnd,
            List<RelationshipDetailsRow> columns,
            List<EdmSchemaError> errors)
        {
            EdmProperty[] fromProperties = new EdmProperty[columns.Count];
            EdmProperty[] toProperties = new EdmProperty[columns.Count];
            EntityType pkEntityType = session.RelationshipEndTypeLookup[pkEnd];
            EntityType fkEntityType = session.RelationshipEndTypeLookup[fkEnd];
            for (int index = 0; index < columns.Count; index++)
            {
                EdmProperty property;

                if(!pkEntityType.Properties.TryGetValue(columns[index].PKColumn, false, out property))
                {
                    errors.Add(
                        new EdmSchemaError(
                          Strings.AssociationMissingKeyColumn(
                            pkEntityType.Name,
                            fkEntityType.Name,
                            pkEntityType.Name + "." + columns[index].PKColumn),
                          (int)ModelBuilderErrorCode.AssociationMissingKeyColumn,
                          EdmSchemaErrorSeverity.Warning));
                    return false;
                }
                fromProperties[index] = property;

                if(!fkEntityType.Properties.TryGetValue(columns[index].FKColumn, false, out property))
                {
                    errors.Add(
                        new EdmSchemaError(
                        Strings.AssociationMissingKeyColumn(
                            pkEntityType.Name,
                            fkEntityType.Name,
                            fkEntityType.Name + "." + columns[index].FKColumn),
                            (int)ModelBuilderErrorCode.AssociationMissingKeyColumn,
                        EdmSchemaErrorSeverity.Warning));
                    return false;
                }
                toProperties[index] = property;
            }

            ReferentialConstraint constraint = new ReferentialConstraint(pkEnd,
                fkEnd,
                fromProperties,
                toProperties);

            association.AddReferentialConstraint(constraint);
            return true;
        }
        private IEnumerable<OneToOneMappingSerializer.CollapsedEntityAssociationSet> FindAllInvalidCollapsedAssociationCandidates(LoadMethodSessionState session)
        {
            Set<OneToOneMappingSerializer.CollapsedEntityAssociationSet> invalid = new Set<OneToOneMappingSerializer.CollapsedEntityAssociationSet>();
            Dictionary<EntitySet, OneToOneMappingSerializer.CollapsedEntityAssociationSet> newCandidates = new Dictionary<EntitySet,OneToOneMappingSerializer.CollapsedEntityAssociationSet>();
            foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.CandidateCollapsedAssociations.Values)
            {
                if (!collapsed.MeetsRequirementsForCollapsableAssociation)
                {
                    invalid.Add(collapsed);
                }
                else
                {
                    newCandidates.Add(collapsed.EntitySet, collapsed);
                }
            }


            foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in newCandidates.Values)
            {
                foreach (AssociationSet set in collapsed.AssociationSets)
                {
                    EntitySet end0Set = set.AssociationSetEnds[0].EntitySet;
                    EntitySet end1Set = set.AssociationSetEnds[1].EntitySet;
                   
                    // if both ends of the association are candidates throw both candidates out
                    // because we can't collapse two entities out
                    // and we don't know which entity we should collapse 
                    // so we won't collapse either
                    if (newCandidates.ContainsKey(end0Set) &&
                        newCandidates.ContainsKey(end1Set))
                    {
                        OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed0 = session.CandidateCollapsedAssociations[end0Set];
                        OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed1 = session.CandidateCollapsedAssociations[end1Set];
                        invalid.Add(collapsed0);
                        invalid.Add(collapsed1);
                    }

                }
            }

            return invalid;
        }
        private void CreateModelNavigationProperties(LoadMethodSessionState session, AssociationType association)
        {
            Debug.Assert(association.Members.Count == 2, "this code assumes two ends");
            AssociationEndMember end1 = (AssociationEndMember)association.Members[0];
            AssociationEndMember end2 = (AssociationEndMember)association.Members[1];

            CreateModelNavigationProperty(session, end1, end2);
            CreateModelNavigationProperty(session, end2, end1);
        }
 private void SaveAssociationForCollapsedAssociationCandidate(LoadMethodSessionState session, AssociationSet storeAssociationSet)
 {
     foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds)
     {
         OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed;
         if (session.CandidateCollapsedAssociations.TryGetValue(end.EntitySet, out collapsed))
         {
             collapsed.AssociationSets.Add(storeAssociationSet);
         }
     }
 }
 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 EntitySet CreateModelEntitySet(LoadMethodSessionState session, EntitySet storeEntitySet)
        {
            EntityType entity = CreateModelEntityType(session, storeEntitySet.ElementType);

            string name = CreateModelName(this._pluralizationServiceHandler.GetEntitySetName(storeEntitySet.Name), session.UsedEntityContainerItemNames);
            
            EntitySet set = new EntitySet(name, null, null, null, entity);
            session.MappingLookups.StoreEntitySetToModelEntitySet.Add(storeEntitySet, set);
            return set;
        }
 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 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, 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 AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, AssociationSet storeAssociationSet)
        {

            AssociationType association;
            // we will get a value when the same association is used for multiple association sets
            if (! session.MappingLookups.StoreAssociationTypeToModelAssociationType.TryGetValue(storeAssociationSet.ElementType, out association))
            {
                association = CreateModelAssociationType(session, storeAssociationSet.ElementType);
                session.MappingLookups.StoreAssociationTypeToModelAssociationType.Add(storeAssociationSet.ElementType, association);
            }

            string name = CreateModelName(storeAssociationSet.Name, session.UsedEntityContainerItemNames);
            AssociationSet set = new AssociationSet(name, association);
            
            foreach(AssociationSetEnd storeEnd in storeAssociationSet.AssociationSetEnds)
            {
                AssociationSetEnd end = CreateModelAssociationSetEnd(session, storeEnd, set);
                session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, end);
                set.AddAssociationSetEnd(end);
            }
            session.MappingLookups.StoreAssociationSetToModelAssociationSet.Add(storeAssociationSet, set);
            return set;
        }
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] //For EdmItemCollection constructor call.  
                                                                            //Since we pass in empty collection for paths, we do not have any resource exposure here.                                                               
        private IList<EdmSchemaError> InternalGenerateMetadata()
        {
            if (_modelEntityContainer != null)
            {
                _modelEntityContainer = null;
                _mappingLookups = null;
                _edmItemCollection = null;
            }

            LoadMethodSessionState session = new LoadMethodSessionState();

            try
            {
                session.EdmItemCollection = new EdmItemCollection();
                if (this.GenerateForeignKeyProperties && this._targetEntityFrameworkVersion < EntityFrameworkVersions.Version2)
                {
                    session.AddError(Strings.UnableToGenerateForeignKeyPropertiesForV1, ModelBuilderErrorCode.UnableToGenerateForeignKeyPropertiesForV1, EdmSchemaErrorSeverity.Error, null);
                    return session.Errors;
                }

                List<AssociationSet> storeAssociationSets = new List<AssociationSet>();
                CollectAllFkProperties(session);

                EntityContainer modelEntityContainer = new EntityContainer(_modelEntityContainerName, DataSpace.CSpace);

                // create the EntityTypes and EntitySets, and save up the AssociationSets for later.
                foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets)
                {
                    switch (storeSet.BuiltInTypeKind)
                    {
                        case BuiltInTypeKind.AssociationSet:
                            // save these, and create them after the EntityTypes and EntitySets have been created
                            string errorMessage;
                            if (this.GenerateForeignKeyProperties || !EntityStoreSchemaGenerator.IsFkPartiallyContainedInPK(((AssociationSet)storeSet).ElementType, out errorMessage))
                            {
                                storeAssociationSets.Add((AssociationSet)storeSet);
                            }
                            else
                            {
                                session.AddError(errorMessage, ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Error, null);
                            }
                            break;
                        case BuiltInTypeKind.EntitySet:
                            EntitySet set = (EntitySet)storeSet;
                            session.CandidateCollapsedAssociations.Add(set, new OneToOneMappingSerializer.CollapsedEntityAssociationSet(set));
                            break;
                        default:
                            // error
                            throw EDesignUtil.MissingGenerationPatternForType(storeSet.BuiltInTypeKind);
                    }
                }

                foreach (AssociationSet storeAssociationSet in storeAssociationSets)
                {
                    SaveAssociationForCollapsedAssociationCandidate(session, storeAssociationSet);
                }

                Set<AssociationSet> associationSetsFromCollapseCandidateRejects = new Set<AssociationSet>();
                IEnumerable<OneToOneMappingSerializer.CollapsedEntityAssociationSet> invalidCandidates = FindAllInvalidCollapsedAssociationCandidates(session);

                // now that we have gone through all of the association sets, 
                foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in invalidCandidates)
                {
                    session.CandidateCollapsedAssociations.Remove(collapsed.EntitySet);

                    // just create the entity set and save the association set to be added later
                    EntitySet entitySet = CreateModelEntitySet(session, collapsed.EntitySet);
                    modelEntityContainer.AddEntitySetBase(entitySet);
                    associationSetsFromCollapseCandidateRejects.AddRange(collapsed.AssociationSets);                        
                }

                // create all the associations for the invalid collapsed entity association candidates
                foreach (AssociationSet storeAssociationSet in (IEnumerable<AssociationSet>)associationSetsFromCollapseCandidateRejects)
                {
                    if (!IsAssociationPartOfCandidateCollapsedAssociation(session, storeAssociationSet))
                    {
                        AssociationSet set = CreateModelAssociationSet(session, storeAssociationSet);
                        modelEntityContainer.AddEntitySetBase(set);
                    }
                }
                
                // save the set that needs to be created and mapped
                session.MappingLookups.CollapsedEntityAssociationSets.AddRange(session.CandidateCollapsedAssociations.Values);

                // do this in a seperate loop so we are sure all the necessary EntitySets have been created
                foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.MappingLookups.CollapsedEntityAssociationSets)
                {
                    AssociationSet set = CreateModelAssociationSet(session, collapsed);
                    modelEntityContainer.AddEntitySetBase(set);
                }
                if (this._targetEntityFrameworkVersion >= EntityFrameworkVersions.Version2)
                {
                    Debug.Assert(EntityFrameworkVersions.Latest == EntityFrameworkVersions.Version3, "Did you add a new framework version");
                    // add LazyLoadingEnabled=true to the EntityContainer
                    MetadataProperty lazyLoadingAttribute =
                        new MetadataProperty(
                            DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.LazyLoadingEnabled,
                            TypeUsage.CreateStringTypeUsage(
                                PrimitiveType.GetEdmPrimitiveType(
                                    PrimitiveTypeKind.String),
                                    false,
                                    false),
                            true);
                    modelEntityContainer.AddMetadataProperties(new List<MetadataProperty>() { lazyLoadingAttribute });
                    this._hasAnnotationNamespace = true;
                }

                // Map store functions to function imports.
                MapFunctions(session, modelEntityContainer);
                
                if (!EntityStoreSchemaGenerator.HasErrorSeverityErrors(session.Errors))
                {
                    // add them to the collection so they will work if someone wants to use the collection
                    foreach (EntityType type in session.MappingLookups.StoreEntityTypeToModelEntityType.Values)
                    {
                        type.SetReadOnly();
                        session.EdmItemCollection.AddInternal(type);
                    }

                    foreach (AssociationType type in session.MappingLookups.StoreAssociationTypeToModelAssociationType.Values)
                    {
                        type.SetReadOnly();
                        session.EdmItemCollection.AddInternal(type);
                    }

                    foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet set in session.MappingLookups.CollapsedEntityAssociationSets)
                    {
                        set.ModelAssociationSet.ElementType.SetReadOnly();
                        session.EdmItemCollection.AddInternal(set.ModelAssociationSet.ElementType);
                    }
                    modelEntityContainer.SetReadOnly();
                    session.EdmItemCollection.AddInternal(modelEntityContainer);

                    _modelEntityContainer = modelEntityContainer;
                    _mappingLookups = session.MappingLookups;
                    _edmItemCollection = session.EdmItemCollection;
                }

            }
            catch (Exception e)
            {
                if (MetadataUtil.IsCatchableExceptionType(e))
                {
                    // an exception in the code is definitely an error
                    string message = EDesignUtil.GetMessagesFromEntireExceptionChain(e);
                    session.AddError(message,
                    ModelBuilderErrorCode.UnknownError,
                    EdmSchemaErrorSeverity.Error,
                    e);
                }
                else
                {
                    throw;
                }

            }
            return session.Errors;
        }
        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;
        }
        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 ReferentialConstraint CreateReferentialConstraint(LoadMethodSessionState session, AssociationType storeAssociation)
        {
            Debug.Assert(session != null, "session parameter is null");
            Debug.Assert(storeAssociation != null, "storeAssociation parameter is null");
            Debug.Assert(storeAssociation.ReferentialConstraints.Count <= 1, "We don't have a reason to have more than one constraint yet");

            // does the store have any constraints
            if (storeAssociation.ReferentialConstraints.Count == 0)
            {    
                return null;
            }

            ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];
            Debug.Assert(storeConstraint.FromProperties.Count == storeConstraint.ToProperties.Count, "FromProperties and ToProperties have different counts");
            Debug.Assert(storeConstraint.FromProperties.Count != 0, "No properties in the constraint, why does the constraint exist?");
            Debug.Assert(storeConstraint.ToProperties[0].DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "The property is not from an EntityType");

            EntityType toType = (EntityType)storeConstraint.ToProperties[0].DeclaringType;
            // If we are generating foreign keys, there is always a referential constraint. Otherwise, check
            // if the dependent end includes key properties. If so, this implies that there is a referential
            // constraint. Otherwise, it is assumed that the foreign key properties are not defined in the 
            // entity (verified ealier).
            if (!this.GenerateForeignKeyProperties && !RequiresModelReferentialConstraint(storeConstraint, toType)) 
            {
                return null;
            }
            // we need a constraint so lets build it
            int count = storeConstraint.FromProperties.Count;
            EdmProperty[] fromProperties = new EdmProperty[count];
            EdmProperty[] toProperties = new EdmProperty[count];
            AssociationEndMember fromRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.FromRole];
            AssociationEndMember toRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.ToRole];
            for (int index = 0; index < count; index++)
            {
                fromProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.FromProperties[index]];
                toProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.ToProperties[index]];
            }

            ReferentialConstraint newConstraint = new ReferentialConstraint(
                fromRole,
                toRole,
                fromProperties,
                toProperties);

            return newConstraint;
        }
        private AssociationSet CreateAssociationSet(LoadMethodSessionState session, 
            AssociationType type)
        {
            AssociationSet set = new AssociationSet(type.Name, type);

            foreach(AssociationEndMember end in type.RelationshipEndMembers)
            {
                EntitySet entitySet = session.GetEntitySet(end);
                DbObjectKey key = session.GetKey(entitySet.ElementType);
                AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end);
                set.AddAssociationSetEnd(setEnd);
            }

            set.SetReadOnly();
            return set;
        }