EntityStoreSchemaGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntityDesign / Design / System / Data / Entity / Design / EntityStoreSchemaGenerator.cs / 5 / EntityStoreSchemaGenerator.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Xml;
using SOM=System.Data.EntityModel;
using System.Globalization;
using System.Data.Metadata.Edm; 
using System.Data.Entity.Design.Common;
using System.Data.Entity.Design.SsdlGenerator; 
using System.Data.Common; 
using System.Data.EntityClient;
using System.IO; 
using System.Data.Mapping;
using System.Data.Common.Utils;
using System.Collections.ObjectModel;
using System.Data.Common.CommandTrees; 
using System.Text;
using System.Linq; 
 
namespace System.Data.Entity.Design
{ 
    /// 
    /// Responsible for Loading Database Schema Information
    /// 
    public sealed partial class EntityStoreSchemaGenerator 
    {
        private const string CONTAINER_SUFFIX = "Container"; 
        private EntityStoreSchemaGeneratorDatabaseSchemaLoader _loader; 
        private readonly string _provider;
        private string _providerManifestToken = string.Empty; 
        private EntityContainer _entityContainer = null;
        private StoreItemCollection _storeItemCollection;
        private string _namespaceName;
        private MetadataItemSerializer.ErrorsLookup _errorsLookup; 
        private List _invalidTypes;
 
        ///  
        /// Creates a new EntityStoreGenerator
        ///  
        /// The name of the provider to use to load the schema information.
        /// A connection string to the DB that should be loaded from.
        /// The namespace name to use for the store metadata that is generated.
        public EntityStoreSchemaGenerator(string providerInvariantName, string connectionString, string namespaceName) 
        {
            EDesignUtil.CheckStringArgument(providerInvariantName, "providerInvariantName"); 
            EDesignUtil.CheckArgumentNull(connectionString, "connectionString"); // check for NULL string and support empty connection string 
            EDesignUtil.CheckStringArgument(namespaceName, "namespaceName");
 
            _namespaceName = EntityModelSchemaGenerator.CreateValidNamespaceName(namespaceName, 'z');
            if (_namespaceName != namespaceName)
            {
                throw EDesignUtil.InvalidNamespaceNameArgument(namespaceName); 
            }
 
            _provider = providerInvariantName; 
            _loader = new EntityStoreSchemaGeneratorDatabaseSchemaLoader(providerInvariantName, connectionString);
        } 



        ///  
        /// Gets the EntityContainer that was created
        ///  
        public EntityContainer EntityContainer 
        {
            get 
            {
                return _entityContainer;
            }
        } 

        ///  
        /// Gets the StoreItemCollection that was created 
        /// 
        public StoreItemCollection StoreItemCollection 
        {
            get
            {
                return _storeItemCollection; 
            }
        } 
 
        /// 
        /// Creates a Metadata schema from the DbSchemaLoader that was passed in 
        /// 
        /// The new metadata for the schema that was loaded
        public IList GenerateStoreMetadata()
        { 
            List filters = new List();
            return GenerateStoreMetadata(filters); 
        } 

 
        /// 
        /// Creates a Metadata schema from the DbSchemaLoader that was passed in
        /// 
        /// The filters to be applied during generation. 
        /// The new metadata for the schema that was loaded
        public IList GenerateStoreMetadata(IEnumerable filters) 
        { 
            EDesignUtil.CheckArgumentNull(filters, "filters");
 
            if (_entityContainer != null)
            {
                _entityContainer = null;
                _storeItemCollection = null; 
                _errorsLookup = null;
                _invalidTypes = null; 
            } 

            LoadMethodSessionState session = new LoadMethodSessionState(); 
            try
            {
                _loader.Open();
 
                DbConnection connection = _loader.InnerConnection;
                DbProviderFactory providerFactory = DbProviderServices.GetProviderFactory(_loader.ProviderInvariantName); 
                DbProviderServices providerServices = DbProviderServices.GetProviderServices(providerFactory); 
                _providerManifestToken = providerServices.GetProviderManifestToken(connection);
                DbProviderManifest storeManifest = providerServices.GetProviderManifest(_providerManifestToken); 

                session.Filters = filters;
                Debug.Assert(_namespaceName != null, "_namespaceName should not be null at this point, did you add a new ctor?");
 
                session.ItemCollection = new StoreItemCollection(providerFactory, providerServices.GetProviderManifest(_providerManifestToken));
 
                CreateTableEntityTypes(session); 
                CreateViewEntityTypes(session);
                string entityContainerName = this._namespaceName.Replace(".", string.Empty) + CONTAINER_SUFFIX; 

                Debug.Assert(entityContainerName != null, "We should always have a container name");
                EntityContainer entityContainer = new EntityContainer(entityContainerName, DataSpace.SSpace);
 

                foreach (EntityType type in session.GetAllEntities()) 
                { 
                    Debug.Assert(type.KeyMembers.Count > 0, "Why do we have Entities without keys in our valid Entities collection");
                    session.ItemCollection.AddInternal(type); 
                    EntitySet entitySet = CreateEntitySet(session, type);
                    session.EntityTypeToSet.Add(type, entitySet);
                    entityContainer.AddEntitySetBase(entitySet);
                } 

                CreateAssociationTypes(session); 
                foreach (AssociationType type in session.AssociationTypes) 
                {
                    session.ItemCollection.AddInternal(type); 
                    AssociationSet set = CreateAssociationSet(session, type);
                    entityContainer.AddEntitySetBase(set);
                }
 
                entityContainer.SetReadOnly();
                session.ItemCollection.AddInternal(entityContainer); 
                FixupKeylessEntitySets(entityContainer, session); 

 

                CreateEdmFunctions(session);
                foreach (EdmFunction function in session.Functions)
                { 
                    function.SetReadOnly();
                    session.ItemCollection.AddInternal(function); 
                } 

                if (!HasErrorSeverityErrors(session.Errors)) 
                {
                    _entityContainer = entityContainer;
                    _storeItemCollection = session.ItemCollection;
                    _errorsLookup = session.ItemToErrorsMap; 
                    _invalidTypes = new List(session.InvalidTypes);
                } 
            } 
            catch (Exception e)
            { 
                if (EntityUtil.IsCatchableExceptionType(e))
                {
                    string message = EDesignUtil.GetMessagesFromEntireExceptionChain(e);
                    session.AddErrorsForType(null, 
                        new EdmSchemaError(message,
                                    (int)ModelBuilderErrorCode.UnknownError, 
                                    EdmSchemaErrorSeverity.Error, 
                                    e));
                } 
                else
                {
                    throw;
                } 
            }
            finally 
            { 
                _loader.Close();
            } 

            return new List(session.Errors);
        }
 
        /// 
        /// Writes the Schema to xml 
        ///  
        /// The name of the file to write the xml to.
        public void WriteStoreSchema(string outputFileName) 
        {
            EDesignUtil.CheckStringArgument(outputFileName, "outputFileName");
            CheckValidItemCollection();
 
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true; 
            using (XmlWriter writer = XmlWriter.Create(outputFileName, settings)) 
            {
                WriteStoreSchema(writer); 
            }
        }

        ///  
        /// Writes the Schema to xml.
        ///  
        /// The XmlWriter to write the xml to. 
        public void WriteStoreSchema(XmlWriter writer)
        { 
            EDesignUtil.CheckArgumentNull(writer, "writer");
            CheckValidItemCollection();

            // we are going to add this EntityStoreSchemaGenerator namespace at the top of 
            // the file so that when we mark the entitysets with where they came from
            // we don't have to repeat the namespace on each node.  The VS tools use 
            // the source information to give better messages when refreshing the .ssdl from the db 
            // e.g.
            // 
            //    
            //   ...
            //  
            var xmlPrefixToNamespace = new KeyValuePair("store", DesignXmlConstants.EntityStoreSchemaGeneratorNamespace); 
            MetadataItemSerializer.WriteXml(writer, StoreItemCollection, _namespaceName, _errorsLookup, _invalidTypes, _provider, _providerManifestToken, xmlPrefixToNamespace);
        } 


        /// 
        /// Creates an EntityConnection loaded with the providers metadata for the 
        /// 
        /// The provider invariant name. 
        /// The connection for the providers connection. 
        /// An EntityConnection that can query the ConceptualSchemaDefinition for the provider.
        public static EntityConnection CreateStoreSchemaConnection(string providerInvariantName, string connectionString) 
        {
            EDesignUtil.CheckArgumentNull(providerInvariantName, "providerInvariantName");
            EDesignUtil.CheckArgumentNull(connectionString, "connectionString");
 
            DbProviderFactory factory;
            try 
            { 
                factory = DbProviderFactories.GetFactory(providerInvariantName);
            } 
            catch (ArgumentException e)
            {
                throw EDesignUtil.Argument(Strings.EntityClient_InvalidStoreProvider(providerInvariantName), e);
            } 

            DbProviderServices providerServices = DbProviderServices.GetProviderServices(factory); 
 
            DbConnection providerConnection = factory.CreateConnection();
            if (providerConnection == null) 
            {
                throw EDesignUtil.ProviderIncompatible(Strings.ProviderFactoryReturnedNullFactory(providerInvariantName));
            }
            providerConnection.ConnectionString = connectionString; 

            MetadataWorkspace workspace = GetProviderSchemaMetadataWorkspace(providerServices, providerConnection); 
 
            // create the connection with the information we have
            return new EntityConnection(workspace, providerConnection); 
        }

        private static MetadataWorkspace GetProviderSchemaMetadataWorkspace(DbProviderServices providerServices, DbConnection providerConnection)
        { 
            XmlReader csdl = null;
            XmlReader ssdl = null; 
            XmlReader msl = null; 

            try 
            {
                // create the metadata workspace
                MetadataWorkspace workspace = new MetadataWorkspace();
 
                string manifestToken = providerServices.GetProviderManifestToken(providerConnection);
                DbProviderManifest providerManifest = providerServices.GetProviderManifest(manifestToken); 
 
                // create the EdmItemCollection
                IList errors; 
                ssdl = providerManifest.GetInformation(DbProviderManifest.StoreSchemaDefinition);
                string location = Strings.DbProviderServicesInformationLocationPath(providerConnection.GetType().Name, DbProviderManifest.StoreSchemaDefinition);
                List ssdlLocations = new List(1);
                ssdlLocations.Add(location); 
                StoreItemCollection storeItemCollection = new StoreItemCollection(new XmlReader[] { ssdl }, ssdlLocations.AsReadOnly(), out errors);
                ThrowOnError(errors); 
                workspace.RegisterItemCollection(storeItemCollection); 

                csdl = DbProviderServices.GetConceptualSchemaDescription(); 
                location = Strings.DbProviderServicesInformationLocationPath(providerConnection.GetType().Name, DbProviderManifest.ConceptualSchemaDefinition);
                List csdlLocations = new List(1);
                csdlLocations.Add(location);
                EdmItemCollection edmItemCollection = new EdmItemCollection(new XmlReader[] { csdl }, csdlLocations.AsReadOnly(), out errors); 
                ThrowOnError(errors);
                workspace.RegisterItemCollection(edmItemCollection); 
 

                msl = providerManifest.GetInformation(DbProviderManifest.StoreSchemaMapping); 
                location = Strings.DbProviderServicesInformationLocationPath(providerConnection.GetType().Name, DbProviderManifest.StoreSchemaMapping);
                List mslLocations = new List(1);
                mslLocations.Add(location);
                StorageMappingItemCollection mappingItemCollection = new StorageMappingItemCollection(edmItemCollection, 
                                                                         storeItemCollection,
                                                                         new XmlReader[] { msl }, 
                                                                         mslLocations, 
                                                                         out errors);
                ThrowOnError(errors); 
                workspace.RegisterItemCollection(mappingItemCollection);

                // make the views generate here so we can wrap the provider schema problems
                // in a ProviderIncompatibleException 
                ForceViewGeneration(workspace);
                return workspace; 
            } 
            catch (ProviderIncompatibleException)
            { 
                // we don't really want to catch this one, just rethrow it
                throw;
            }
            catch (Exception e) 
            {
                if (EntityUtil.IsCatchableExceptionType(e)) 
                { 
                    throw EDesignUtil.ProviderIncompatible(Strings.ProviderSchemaErrors, e);
                } 

                throw;
            }
            finally 
            {
                if (csdl != null) ((IDisposable)csdl).Dispose(); 
                if (ssdl != null) ((IDisposable)ssdl).Dispose(); 
                if (msl != null) ((IDisposable)msl).Dispose();
            } 
        }

        private static void ForceViewGeneration(MetadataWorkspace workspace)
        { 
            ReadOnlyCollection containers = workspace.GetItems(DataSpace.SSpace);
            Debug.Assert(containers.Count != 0, "no s space containers found"); 
            Debug.Assert(containers[0].BaseEntitySets.Count != 0, "no entity sets in the sspace container"); 
            workspace.GetCqtView(containers[0].BaseEntitySets[0]);
        } 

        private static void ThrowOnError(IList errors)
        {
            if (errors.Count != 0) 
            {
                if (!MetadataHelper.CheckIfAllErrorsAreWarnings(errors)) 
                { 
                    throw EDesignUtil.ProviderIncompatible(Strings.ProviderSchemaErrors, EntityUtil.InvalidSchemaEncountered(Helper.CombineErrorMessage(errors)));
                } 
            }
        }

        private void CheckValidItemCollection() 
        {
            if (_entityContainer == null) 
            { 
                throw EDesignUtil.EntityStoreGeneratorSchemaNotLoaded();
            } 
        }

        internal static bool HasErrorSeverityErrors(IEnumerable errors)
        { 
            foreach (EdmSchemaError error in errors)
            { 
                if (error.Severity == EdmSchemaErrorSeverity.Error) 
                {
                    return true; 
                }
            }
            return false;
        } 

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

        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.CreateMetadataPropertyFromOtherNamespaceXmlAttribute(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorTypeAttributeName, GetSourceNameFromObjectType(key.ObjectType));
            List properties = new List(); 
            properties.Add(property);
            entitySet.AddMetadataProperties(properties);
            entitySet.SetReadOnly();
            return entitySet; 
        }
 
        private string GetSourceNameFromObjectType(DbObjectType dbObjectType) 
        {
            switch(dbObjectType) 
            {
                case DbObjectType.Table:
                    return DesignXmlConstants.TypeValueTables;
                default: 
                    Debug.Assert(dbObjectType == DbObjectType.View, "did you change to a call that could have different types?");
                    return DesignXmlConstants.TypeValueViews; 
            } 
        }
 
        private void CreateEdmFunctions(LoadMethodSessionState session)
        {
            using(FunctionDetailsReader reader = _loader.LoadStoredProcedureDetails(session.Filters))
            { 
                DbObjectKey currentFunction = new DbObjectKey();
                List parameters = new List(); 
                while(reader.Read()) 
                {
                    DbObjectKey rowFunction = reader.CreateDbObjectKey(); 
                    if (rowFunction != currentFunction)
                    {
                        if (!currentFunction.IsEmpty)
                        { 
                            CreateEdmFunction(session, parameters);
                            parameters.Clear(); 
                        } 
                        currentFunction = rowFunction;
                    } 
                    parameters.Add(reader.CreateMemento());
                }

                if (parameters.Count != 0) 
                {
                    CreateEdmFunction(session, parameters); 
                } 

            } 
        }

        private void CreateEdmFunction(LoadMethodSessionState session, List 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 errors = new List();
            if (!row.IsReturnTypeNull)
            { 
                TypeUsage returnType = GetFunctionTypeUsage(session, row.ReturnType);
                if (returnType != null) 
                { 
                    returnParameter = new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue);
                } 
                else
                {
                    isValid = false;
                    errors.Add(new EdmSchemaError( 
                        Strings.UnsupportedFunctionReturnDataType(
                            row.ProcedureName, 
                            row.ReturnType), 
                        (int)ModelBuilderErrorCode.UnsupportedType,
                        EdmSchemaErrorSeverity.Warning)); 
                }
            }

 
            bool caseSensitive = false;
            UniqueIdentifierService uniqueIdentifiers = new UniqueIdentifierService(caseSensitive); 
            List functionParameters = new List(); 
            for (int i = 0; i < parameters.Count && !row.IsParameterNameNull; i++)
            { 
                row.Attach(parameters[i]);
                TypeUsage parameterType = null;
                if(!row.IsParameterTypeNull)
                { 
                    parameterType = GetFunctionTypeUsage(session, row.ParameterType);
                } 
 
                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( 
                        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);
            EdmFunction function = new EdmFunction(functionName,
                _namespaceName,
                DataSpace.SSpace, 
                new EdmFunctionPayload
                { 
                    Schema = row.IsSchemaNull ? null : row.Schema, 
                    StoreFunctionName = functionName != row.ProcedureName ? row.ProcedureName : null,
                    IsAggregate = row.IsIsAggregate, 
                    IsBuiltIn = row.IsBuiltIn,
                    IsNiladic = row.IsNiladic,
                    IsComposable = row.IsComposable,
                    ReturnParameter = returnParameter, 
                    Parameters = functionParameters.ToArray()
                }); 
 

            session.AddErrorsForType(function, errors); 
            if (isValid)
            {
                session.Functions.Add(function);
            } 
            else
            { 
                session.InvalidTypes.Add(function); 
            }
        } 

        private TypeUsage GetFunctionTypeUsage(LoadMethodSessionState session, string dataType)
        {
            PrimitiveType primitiveType; 
            if (session.TryGetStorePrimitiveType(dataType, out primitiveType))
            { 
                TypeUsage usage = TypeUsage.Create(primitiveType, FacetValues.NullFacetValues); 
                return usage;
            } 
            return null;
        }

        private void CreateAssociationTypes(LoadMethodSessionState session) 
        {
            RelationshipDetailsCollection relationships = _loader.LoadRelationships(session.Filters); 
 
            string currentRelationshipId = string.Empty;
            List columns = new List(); 
            foreach (RelationshipDetailsRow row in relationships.Rows)
            {
                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 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 allFkColumnsAreNullable = AreAllFkKeyColumnsNullable(fkEntityType, columns);
            RelationshipMultiplicity pkMultiplicity = allFkColumnsAreNullable ? 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 ( !allFkColumnsAreNullable && 
                 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, DataSpace.SSpace);
            type.AddMember(pkEnd); 
            type.AddMember(fkEnd);

            List errors = new List();
            bool isValid = CreateReferentialConstraint(session, 
                        type,
                        pkEnd, 
                        fkEnd, 
                        columns,
                        errors); 


            string errorMessage;
            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 toPropertyOfAddedAssc 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(toPropertyOfAddedAssc.DeclaringType) && toProperty.Equals(toPropertyOfAddedAssc))
                        { 
                            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 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 static bool AreRelationshipColumnsTheTypesEntireKey(
            EntityType entity, 
            List columns,
            Func getColumnName)
        {
            if (entity.KeyMembers.Count != columns.Count) 
            {
                // to be the entire key, 
                // must have the same number of columns 
                return false;
            } 

            foreach (RelationshipDetailsRow row in columns)
            {
                if (!entity.KeyMembers.Contains(getColumnName(row))) 
                {
                    // not a key 
                    return false; 
                }
            } 
            return true;
        }

        private static bool AreAllFkKeyColumnsNullable( 
            EntityType entity,
            List columns) 
        { 
            foreach (RelationshipDetailsRow row in columns)
            { 
                EdmProperty property;
                if (entity.Properties.TryGetValue(row.FKColumn, false, out property))
                {
                    if (!property.Nullable) 
                    {
                        return false; 
                    } 
                }
                else 
                {
                    Debug.Fail("Why didn't we find the column?");
                    return false;
                } 
            }
            return true; 
        } 

 
        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 bool CreateReferentialConstraint(LoadMethodSessionState session, 
            AssociationType association,
            AssociationEndMember pkEnd, 
            AssociationEndMember fkEnd,
            List columns,
            List 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;
        } 

        static internal bool IsFkPartiallyContainedInPK(AssociationType association, out string errorMessage) 
        { 
            ReferentialConstraint constraint = association.ReferentialConstraints[0];
            EntityType toType = (EntityType)constraint.ToProperties[0].DeclaringType; 

            bool toPropertiesAreFullyContainedInPk = true;
            bool toPropertiesContainedAtLeastOnePK = false;
 
            foreach (EdmProperty edmProperty in constraint.ToProperties)
            { 
                // check if there is at least one to property is not primary key 
                toPropertiesAreFullyContainedInPk &= toType.KeyMembers.Contains(edmProperty);
                // check if there is one to property is primary key 
                toPropertiesContainedAtLeastOnePK |= toType.KeyMembers.Contains(edmProperty);
            }
            if (!toPropertiesAreFullyContainedInPk && toPropertiesContainedAtLeastOnePK)
            { 
                string foreignKeys = MembersToCommaSeparatedString((System.Collections.IEnumerable)constraint.ToProperties);
                string primaryKeys = MembersToCommaSeparatedString((System.Collections.IEnumerable)toType.KeyMembers); 
                errorMessage = Strings.UnsupportedForeignKeyPattern(association.Name, foreignKeys, primaryKeys, toType.Name); 
                return true;
            } 
            errorMessage = "";
            return false;
        }
 
        private static string MembersToCommaSeparatedString(System.Collections.IEnumerable members)
        { 
            StringBuilder builder = new StringBuilder(); 
            builder.Append("{");
            StringUtil.ToCommaSeparatedString(builder, members); 
            builder.Append("}");
            return builder.ToString();
        }
 
        private void CreateViewEntityTypes(LoadMethodSessionState session)
        { 
            TableDetailsCollection viewDetails = _loader.LoadViewDetails(session.Filters); 
            CreateEntityTypes(session, viewDetails, DbObjectType.View);
        } 

        private void CreateTableEntityTypes(LoadMethodSessionState session)
        {
            TableDetailsCollection tableDetails = _loader.LoadTableDetails(session.Filters); 
            CreateEntityTypes(session, tableDetails, DbObjectType.Table);
        } 
 
        private void CreateEntityTypes(LoadMethodSessionState session, TableDetailsCollection details, DbObjectType objectType)
        { 

            DbObjectKey currentKey = new DbObjectKey();
            List singleTableColumns = new List();
            List primaryKeys = new List(); 
            foreach (TableDetailsRow row in details.Rows)
            { 
                DbObjectKey rowKey = CreateDbObjectKey(row, objectType); 
                if (rowKey != currentKey)
                { 
                    if (singleTableColumns.Count != 0)
                    {
                        CreateEntityType(
                            session, 
                            singleTableColumns,
                            primaryKeys, 
                            objectType, 
                            null);
 
                        singleTableColumns.Clear();
                        primaryKeys.Clear();
                    }
                    currentKey = rowKey; 
                }
 
                singleTableColumns.Add(row); 
                if (row.IsPrimaryKey)
                { 
                    primaryKeys.Add(row.ColumnName);
                }
            }
 
            // pick up the last one
            if (singleTableColumns.Count != 0) 
            { 
                CreateEntityType(
                            session, 
                            singleTableColumns,
                            primaryKeys,
                            objectType,
                            null); 

            } 
        } 

        private void CreateEntityType(LoadMethodSessionState session, 
            IList columns,
            ICollection primaryKeys,
            DbObjectType objectType,
            List errors) 
        {
            Debug.Assert(columns.Count != 0, "Trying to create an EntityType with 0 properties"); 
 
            //
            // Handle Tables without explicit declaration of keys 
            //
            DbObjectKey tableKey = CreateDbObjectKey(columns[0], objectType);
            EntityCreationStatus status = EntityCreationStatus.Normal;
            if (errors == null) 
            {
                errors = new List(); 
            } 

            if (primaryKeys.Count == 0) 
            {
                List pKeys = new List(columns.Count);
                session.AddTableWithoutKey(tableKey);
                if (InferKeyColumns(session, columns, pKeys, tableKey, ref primaryKeys)) 
                {
                    errors.Add(new EdmSchemaError( 
                        Strings.NoPrimaryKeyDefined(tableKey), 
                                    (int)ModelBuilderErrorCode.NoPrimaryKeyDefined,
                                     EdmSchemaErrorSeverity.Warning)); 
                    status = EntityCreationStatus.ReadOnly;
                }
                else
                { 
                    errors.Add(new EdmSchemaError(
                        Strings.CannotCreateEntityWithNoPrimaryKeyDefined(tableKey), 
                                        (int)ModelBuilderErrorCode.CannotCreateEntityWithoutPrimaryKey, 
                                        EdmSchemaErrorSeverity.Warning));
                    status = EntityCreationStatus.Invalid; 
                }
            }

            Debug.Assert(primaryKeys == null || primaryKeys.Count > 0,"There must be at least one key columns at this point in time"); 

            List members = new List(); 
            List excludedKeyColumns = new List(); 
            foreach (TableDetailsRow row in columns)
            { 
                bool isPartOfKey = primaryKeys != null && primaryKeys.Contains(row.ColumnName);
                PrimitiveType primitiveType;
                if ( row.IsDataTypeNull() || !session.TryGetStorePrimitiveType(row.DataType, out primitiveType))
                { 
                    string message;
                    if(!row.IsDataTypeNull()) 
                    { 
                        message = Strings.UnsupportedDataType(row.DataType, row.GetMostQualifiedTableName(), row.ColumnName);
                    } 
                    else
                    {
                        message = Strings.UnsupportedDataTypeUnknownType(row.ColumnName, row.GetMostQualifiedTableName());
                    } 

                    errors.Add(new EdmSchemaError(message, 
                        (int)ModelBuilderErrorCode.UnsupportedType, EdmSchemaErrorSeverity.Warning)); 

                    if(isPartOfKey) 
                    {
                        excludedKeyColumns.Add(row.ColumnName);
                    }
                    continue; 
                }
 
                if (isPartOfKey && !Helper.IsValidKeyType(primitiveType.PrimitiveTypeKind)) 
                {
                    // make it a read-only table by calling this method recursivly with no keys 
                    List priorErrors = new List();
                    priorErrors.Add(new EdmSchemaError(Strings.InvalidTypeForPrimaryKey(row.GetMostQualifiedTableName(),
                        row.ColumnName,
                        row.DataType), 
                        (int)ModelBuilderErrorCode.InvalidKeyTypeFound,
                        EdmSchemaErrorSeverity.Warning)); 
 

                    string[] keyColumns = new string[0]; 
                    CreateEntityType(session, columns, keyColumns, objectType, priorErrors);
                    return;
                }
 
                Dictionary facets = primitiveType.GetAssociatedFacetDescriptions().ToDictionary(fd => fd.FacetName, fd => fd.DefaultValueFacet);
                facets[DbProviderManifest.NullableFacetName] = Facet.Create(facets[DbProviderManifest.NullableFacetName].Description, row.IsNullable); 
 
                if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Decimal)
                { 
                    Facet precision;
                    if (facets.TryGetValue(DbProviderManifest.PrecisionFacetName, out precision))
                    {
                        if (!row.IsPrecisionNull() && !precision.Description.IsConstant) 
                        {
                            if (row.Precision < precision.Description.MinValue || row.Precision > precision.Description.MaxValue) 
                            { 
                                DbObjectKey key = CreateDbObjectKey(row, objectType);
                                errors.Add(new EdmSchemaError( 
                                    Strings.ColumnFacetValueOutOfRange(
                                        DbProviderManifest.PrecisionFacetName,
                                        row.Precision,
                                        precision.Description.MinValue, 
                                        precision.Description.MaxValue,
                                        row.ColumnName, 
                                        key), 
                                    (int)ModelBuilderErrorCode.FacetValueOutOfRange,
                                    EdmSchemaErrorSeverity.Warning)); 
                                if (isPartOfKey)
                                {
                                    excludedKeyColumns.Add(row.ColumnName);
                                } 
                                continue;
                            } 
                            facets[precision.Name] = Facet.Create(precision.Description, (byte)row.Precision); 
                        }
                    } 
                    Facet scale;
                    if (facets.TryGetValue(DbProviderManifest.ScaleFacetName, out scale))
                    {
                        if (!row.IsScaleNull() && !scale.Description.IsConstant) 
                        {
                            if (row.Scale < scale.Description.MinValue || row.Scale > scale.Description.MaxValue) 
                            { 
                                DbObjectKey key = CreateDbObjectKey(row, objectType);
                                errors.Add(new EdmSchemaError( 
                                    Strings.ColumnFacetValueOutOfRange(
                                        DbProviderManifest.ScaleFacetName,
                                        row.Scale,
                                        scale.Description.MinValue, 
                                        scale.Description.MaxValue,
                                        row.ColumnName, 
                                        key), 
                                    (int)ModelBuilderErrorCode.FacetValueOutOfRange,
                                    EdmSchemaErrorSeverity.Warning)); 
                                if (isPartOfKey)
                                {
                                    excludedKeyColumns.Add(row.ColumnName);
                                } 
                                continue;
                            } 
                            facets[scale.Name] = Facet.Create(scale.Description, (byte)row.Scale); 
                        }
                    } 
                }
                else if ((primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.DateTime) || (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Time)
                        || (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.DateTimeOffset))
                { 
                    Facet datetimePrecision;
                    if (facets.TryGetValue(DbProviderManifest.PrecisionFacetName, out datetimePrecision)) 
                    { 
                        if (!row.IsDateTimePrecisionNull() && !datetimePrecision.Description.IsConstant)
                        { 
                            if (row.DateTimePrecision < datetimePrecision.Description.MinValue || row.DateTimePrecision > datetimePrecision.Description.MaxValue)
                            {
                                DbObjectKey key = CreateDbObjectKey(row, objectType);
                                errors.Add(new EdmSchemaError( 
                                    Strings.ColumnFacetValueOutOfRange(
                                        DbProviderManifest.PrecisionFacetName, 
                                        row.DateTimePrecision, 
                                        datetimePrecision.Description.MinValue,
                                        datetimePrecision.Description.MaxValue, 
                                        row.ColumnName,
                                        key),
                                    (int)ModelBuilderErrorCode.FacetValueOutOfRange,
                                    EdmSchemaErrorSeverity.Warning)); 
                                if (isPartOfKey)
                                { 
                                    excludedKeyColumns.Add(row.ColumnName); 
                                }
                                continue; 
                            }
                            facets[datetimePrecision.Name] = Facet.Create(datetimePrecision.Description, (byte)row.DateTimePrecision);
                        }
                    } 
                }
                else if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String || 
                       primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary) 
                {
                    Facet maxLength; 
                    if (facets.TryGetValue(DbProviderManifest.MaxLengthFacetName, out maxLength))
                    {
                        if (!row.IsMaximumLengthNull() && !maxLength.Description.IsConstant)
                        { 
                            if (row.MaximumLength < maxLength.Description.MinValue || row.MaximumLength > maxLength.Description.MaxValue)
                            { 
                                DbObjectKey key = CreateDbObjectKey(row, objectType); 
                                errors.Add(new EdmSchemaError(
                                    Strings.ColumnFacetValueOutOfRange( 
                                        DbProviderManifest.MaxLengthFacetName,
                                        row.MaximumLength,
                                        maxLength.Description.MinValue,
                                        maxLength.Description.MaxValue, 
                                        row.ColumnName,
                                        key), 
                                    (int)ModelBuilderErrorCode.FacetValueOutOfRange, 
                                    EdmSchemaErrorSeverity.Warning));
                                if (isPartOfKey) 
                                {
                                    excludedKeyColumns.Add(row.ColumnName);
                                }
                                continue; 
                            }
                            facets[maxLength.Name] = Facet.Create(maxLength.Description, row.MaximumLength); 
                        } 
                    }
                } 

                if (!row.IsIsIdentityNull() && row.IsIdentity)
                {
                    Facet facet = Facet.Create(System.Data.Metadata.Edm.Converter.StoreGeneratedPatternFacet, StoreGeneratedPattern.Identity); 
                    facets.Add(facet.Name, facet);
                } 
                else if (!row.IsIsServerGeneratedNull() && row.IsServerGenerated) 
                {
                    Facet facet = Facet.Create(System.Data.Metadata.Edm.Converter.StoreGeneratedPatternFacet, StoreGeneratedPattern.Computed); 
                    facets.Add(facet.Name, facet);
                }

 
                members.Add(new EdmProperty(row.ColumnName, TypeUsage.Create(primitiveType, facets.Values)));
            } 
 
            if (excludedKeyColumns.Count > 0)
            { 
                // see if we have any keys left
                if (primaryKeys != null && excludedKeyColumns.Count < primaryKeys.Count)
                {
                    List newKeys = new List(); 
                    foreach (string key in primaryKeys)
                    { 
                        if (!excludedKeyColumns.Contains(key)) 
                        {
                            newKeys.Add(key); 
                        }
                    }
                    primaryKeys = newKeys;
                    status = EntityCreationStatus.ReadOnly; 
                }
                else 
                { 
                    primaryKeys = null;
                    status = EntityCreationStatus.Invalid; 
                }

                foreach (string columnName in excludedKeyColumns)
                { 
                    if (status == EntityCreationStatus.ReadOnly)
                    { 
                        errors.Add(new EdmSchemaError( 
                            Strings.ExcludedColumnWasAKeyColumnEntityIsReadOnly(columnName, columns[0].GetMostQualifiedTableName()),
                            (int)ModelBuilderErrorCode.ExcludedColumnWasAKeyColumn, 
                            EdmSchemaErrorSeverity.Warning));
                    }
                    else
                    { 
                        Debug.Assert(status == EntityCreationStatus.Invalid, "Did we change some code above to make it possible to be something different?");
                        errors.Add(new EdmSchemaError( 
                            Strings.ExcludedColumnWasAKeyColumnEntityIsInvalid(columnName, columns[0].GetMostQualifiedTableName()), 
                            (int)ModelBuilderErrorCode.ExcludedColumnWasAKeyColumn,
                            EdmSchemaErrorSeverity.Warning)); 
                    }
                }
            }
 
            string typeName = session.UsedTypeNames.AdjustIdentifier(columns[0].TableName);
            EntityType entityType = new EntityType(typeName, _namespaceName, DataSpace.SSpace, 
                primaryKeys, 
                members);
 
            switch (status)
            {
                case EntityCreationStatus.Normal:
                    session.AddEntity(tableKey, entityType); 
                    break;
                case EntityCreationStatus.ReadOnly: 
                    session.AddEntity(tableKey, entityType); 
                    session.ReadOnlyEntities.Add(entityType);
                    break; 
                default:
                    Debug.Assert(status == EntityCreationStatus.Invalid, "did you add a new value?");
                    session.InvalidTypes.Add(entityType);
                    break; 
            }
 
            entityType.SetReadOnly(); 
            session.AddErrorsForType(entityType, errors);
        } 

        private static bool InferKeyColumns(LoadMethodSessionState session, IList columns, List pKeys, DbObjectKey tableKey, ref ICollection primaryKeys)
        {
            for (int i = 0; i < columns.Count; i++) 
            {
                if (!columns[i].IsNullable) 
                { 
                    PrimitiveType primitiveType;
                    if (session.TryGetStorePrimitiveType(columns[i].DataType, out primitiveType) && 
                        Helper.IsValidKeyType(primitiveType.PrimitiveTypeKind) )
                    {
                        pKeys.Add(columns[i].ColumnName);
                    } 
                }
            } 
 
            // if there are valid key column candidates, make them the new key columns
            if (pKeys.Count > 0) 
            {
                primaryKeys = pKeys;
            }
            else 
            {
                primaryKeys = null; 
            } 

            return primaryKeys != null; 
        }

        private DbObjectKey CreateDbObjectKey(TableDetailsRow row, DbObjectType objectType)
        { 
            TableDetailsCollection table = row.Table;
            return new DbObjectKey(row[table.CatalogColumn], 
                row[table.SchemaColumn], 
                row[table.TableNameColumn], objectType);
        } 

        /// 
        /// Populates DefiningQuery attribute of RO view entities
        ///  
        /// 
        ///  
        ///  
        private void FixupKeylessEntitySets(EntityContainer entityContainer, LoadMethodSessionState session)
        { 
            // if there are views to process
            if (session.ReadOnlyEntities.Count > 0)
            {
                // 
                // create 'bogus' metadataworkspace
                // 
                MetadataWorkspace metadataWorkspace = CreateMetadataWorkspace(entityContainer, session); 

                // 
                // For all tables/views that we could infer valid keys, update DefiningQuery with
                // provider specific ReadOnly view SQL
                //
                foreach (EntityType entityType in session.ReadOnlyEntities) 
                {
                    EntitySet entitySet = session.EntityTypeToSet[entityType]; 
                    DbObjectKey key = session.GetKey(entityType); 

                    // add properties that make it possible for the designer to track back these 
                    // types to their source db objects
                    List properties = new List();
                    if (key.Schema != null)
                    { 
                        properties.Add(System.Data.EntityModel.SchemaObjectModel.SchemaElement.CreateMetadataPropertyFromOtherNamespaceXmlAttribute(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorSchemaAttributeName, key.Schema));
                    } 
                    properties.Add(System.Data.EntityModel.SchemaObjectModel.SchemaElement.CreateMetadataPropertyFromOtherNamespaceXmlAttribute(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorNameAttributeName, key.TableName)); 
                    entitySet.AddMetadataProperties(properties);
 
                    FixupViewEntitySetDefiningQuery(entitySet, metadataWorkspace);
                }
            }
        } 

        ///  
        /// Creates 'transient' metadataworkspace based on store schema (EntityContainer) and trivial C-S mapping 
        /// 
        ///  
        /// 
        /// 
        private MetadataWorkspace CreateMetadataWorkspace(EntityContainer entityContainer, LoadMethodSessionState session)
        { 
            MetadataWorkspace metadataWorkspace = new MetadataWorkspace();
 
            EntityModelSchemaGenerator modelGen = new EntityModelSchemaGenerator(entityContainer); 
            modelGen.GenerateMetadata();
 
            // register edmitemcollection
            metadataWorkspace.RegisterItemCollection(modelGen.EdmItemCollection);

            // register StoreItemCollection 
            metadataWorkspace.RegisterItemCollection(session.ItemCollection);
 
            // register mapping 
            using (MemoryStream memStream = new MemoryStream())
            { 
                using (XmlWriter xmlWriter = XmlWriter.Create(memStream))
                {
                    modelGen.WriteStorageMapping(xmlWriter);
                    xmlWriter.Close(); 
                }
 
                memStream.Seek(0, SeekOrigin.Begin); 

                using (XmlReader xmlReader = XmlReader.Create(memStream)) 
                {
                    List xmlReaders = new List();
                    xmlReaders.Add(xmlReader);
                    metadataWorkspace.RegisterItemCollection(new StorageMappingItemCollection(modelGen.EdmItemCollection, 
                                                                                              session.ItemCollection,
                                                                                              xmlReaders)); 
                } 
            }
 
            return metadataWorkspace;
        }

        ///  
        /// Generates provider specific, read only SQL and updates entitySet DefiningQuery
        ///  
        ///  
        /// 
        private void FixupViewEntitySetDefiningQuery(EntitySet entitySet, MetadataWorkspace metadataWorkspace) 
        {
            DbQueryCommandTree dbCommandTree = new DbQueryCommandTree(metadataWorkspace, DataSpace.SSpace);
            DbExpressionBinding inputBinding = dbCommandTree.CreateExpressionBinding(dbCommandTree.CreateScanExpression(entitySet), entitySet.Name);
            List> projectList = new List>(entitySet.ElementType.Members.Count); 
            foreach (EdmMember member in entitySet.ElementType.Members)
            { 
                Debug.Assert(member.BuiltInTypeKind == BuiltInTypeKind.EdmProperty, "Every member must be a edmproperty"); 
                EdmProperty propertyInfo = (EdmProperty)member;
                projectList.Add(new KeyValuePair(member.Name, 
                                                                       dbCommandTree.CreatePropertyExpression(propertyInfo,
                                                                                                              inputBinding.Variable)));
            }
            dbCommandTree.Query = dbCommandTree.CreateProjectExpression(inputBinding, 
                                                                        dbCommandTree.CreateNewRowExpression(projectList));
            dbCommandTree.Validate(); 
 
            //
            // get provider SQL and set entitySet DefiningQuery 
            //
            entitySet.DefiningQuery = (DbProviderServices.GetProviderServices(_loader.EntityConnection.StoreProviderFactory)
                                                            .CreateCommandDefinition(dbCommandTree))
                                                                .CreateCommand().CommandText; 

            Debug.Assert(!String.IsNullOrEmpty(entitySet.DefiningQuery), "DefiningQuery must not be null or empty"); 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Xml;
using SOM=System.Data.EntityModel;
using System.Globalization;
using System.Data.Metadata.Edm; 
using System.Data.Entity.Design.Common;
using System.Data.Entity.Design.SsdlGenerator; 
using System.Data.Common; 
using System.Data.EntityClient;
using System.IO; 
using System.Data.Mapping;
using System.Data.Common.Utils;
using System.Collections.ObjectModel;
using System.Data.Common.CommandTrees; 
using System.Text;
using System.Linq; 
 
namespace System.Data.Entity.Design
{ 
    /// 
    /// Responsible for Loading Database Schema Information
    /// 
    public sealed partial class EntityStoreSchemaGenerator 
    {
        private const string CONTAINER_SUFFIX = "Container"; 
        private EntityStoreSchemaGeneratorDatabaseSchemaLoader _loader; 
        private readonly string _provider;
        private string _providerManifestToken = string.Empty; 
        private EntityContainer _entityContainer = null;
        private StoreItemCollection _storeItemCollection;
        private string _namespaceName;
        private MetadataItemSerializer.ErrorsLookup _errorsLookup; 
        private List _invalidTypes;
 
        ///  
        /// Creates a new EntityStoreGenerator
        ///  
        /// The name of the provider to use to load the schema information.
        /// A connection string to the DB that should be loaded from.
        /// The namespace name to use for the store metadata that is generated.
        public EntityStoreSchemaGenerator(string providerInvariantName, string connectionString, string namespaceName) 
        {
            EDesignUtil.CheckStringArgument(providerInvariantName, "providerInvariantName"); 
            EDesignUtil.CheckArgumentNull(connectionString, "connectionString"); // check for NULL string and support empty connection string 
            EDesignUtil.CheckStringArgument(namespaceName, "namespaceName");
 
            _namespaceName = EntityModelSchemaGenerator.CreateValidNamespaceName(namespaceName, 'z');
            if (_namespaceName != namespaceName)
            {
                throw EDesignUtil.InvalidNamespaceNameArgument(namespaceName); 
            }
 
            _provider = providerInvariantName; 
            _loader = new EntityStoreSchemaGeneratorDatabaseSchemaLoader(providerInvariantName, connectionString);
        } 



        ///  
        /// Gets the EntityContainer that was created
        ///  
        public EntityContainer EntityContainer 
        {
            get 
            {
                return _entityContainer;
            }
        } 

        ///  
        /// Gets the StoreItemCollection that was created 
        /// 
        public StoreItemCollection StoreItemCollection 
        {
            get
            {
                return _storeItemCollection; 
            }
        } 
 
        /// 
        /// Creates a Metadata schema from the DbSchemaLoader that was passed in 
        /// 
        /// The new metadata for the schema that was loaded
        public IList GenerateStoreMetadata()
        { 
            List filters = new List();
            return GenerateStoreMetadata(filters); 
        } 

 
        /// 
        /// Creates a Metadata schema from the DbSchemaLoader that was passed in
        /// 
        /// The filters to be applied during generation. 
        /// The new metadata for the schema that was loaded
        public IList GenerateStoreMetadata(IEnumerable filters) 
        { 
            EDesignUtil.CheckArgumentNull(filters, "filters");
 
            if (_entityContainer != null)
            {
                _entityContainer = null;
                _storeItemCollection = null; 
                _errorsLookup = null;
                _invalidTypes = null; 
            } 

            LoadMethodSessionState session = new LoadMethodSessionState(); 
            try
            {
                _loader.Open();
 
                DbConnection connection = _loader.InnerConnection;
                DbProviderFactory providerFactory = DbProviderServices.GetProviderFactory(_loader.ProviderInvariantName); 
                DbProviderServices providerServices = DbProviderServices.GetProviderServices(providerFactory); 
                _providerManifestToken = providerServices.GetProviderManifestToken(connection);
                DbProviderManifest storeManifest = providerServices.GetProviderManifest(_providerManifestToken); 

                session.Filters = filters;
                Debug.Assert(_namespaceName != null, "_namespaceName should not be null at this point, did you add a new ctor?");
 
                session.ItemCollection = new StoreItemCollection(providerFactory, providerServices.GetProviderManifest(_providerManifestToken));
 
                CreateTableEntityTypes(session); 
                CreateViewEntityTypes(session);
                string entityContainerName = this._namespaceName.Replace(".", string.Empty) + CONTAINER_SUFFIX; 

                Debug.Assert(entityContainerName != null, "We should always have a container name");
                EntityContainer entityContainer = new EntityContainer(entityContainerName, DataSpace.SSpace);
 

                foreach (EntityType type in session.GetAllEntities()) 
                { 
                    Debug.Assert(type.KeyMembers.Count > 0, "Why do we have Entities without keys in our valid Entities collection");
                    session.ItemCollection.AddInternal(type); 
                    EntitySet entitySet = CreateEntitySet(session, type);
                    session.EntityTypeToSet.Add(type, entitySet);
                    entityContainer.AddEntitySetBase(entitySet);
                } 

                CreateAssociationTypes(session); 
                foreach (AssociationType type in session.AssociationTypes) 
                {
                    session.ItemCollection.AddInternal(type); 
                    AssociationSet set = CreateAssociationSet(session, type);
                    entityContainer.AddEntitySetBase(set);
                }
 
                entityContainer.SetReadOnly();
                session.ItemCollection.AddInternal(entityContainer); 
                FixupKeylessEntitySets(entityContainer, session); 

 

                CreateEdmFunctions(session);
                foreach (EdmFunction function in session.Functions)
                { 
                    function.SetReadOnly();
                    session.ItemCollection.AddInternal(function); 
                } 

                if (!HasErrorSeverityErrors(session.Errors)) 
                {
                    _entityContainer = entityContainer;
                    _storeItemCollection = session.ItemCollection;
                    _errorsLookup = session.ItemToErrorsMap; 
                    _invalidTypes = new List(session.InvalidTypes);
                } 
            } 
            catch (Exception e)
            { 
                if (EntityUtil.IsCatchableExceptionType(e))
                {
                    string message = EDesignUtil.GetMessagesFromEntireExceptionChain(e);
                    session.AddErrorsForType(null, 
                        new EdmSchemaError(message,
                                    (int)ModelBuilderErrorCode.UnknownError, 
                                    EdmSchemaErrorSeverity.Error, 
                                    e));
                } 
                else
                {
                    throw;
                } 
            }
            finally 
            { 
                _loader.Close();
            } 

            return new List(session.Errors);
        }
 
        /// 
        /// Writes the Schema to xml 
        ///  
        /// The name of the file to write the xml to.
        public void WriteStoreSchema(string outputFileName) 
        {
            EDesignUtil.CheckStringArgument(outputFileName, "outputFileName");
            CheckValidItemCollection();
 
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true; 
            using (XmlWriter writer = XmlWriter.Create(outputFileName, settings)) 
            {
                WriteStoreSchema(writer); 
            }
        }

        ///  
        /// Writes the Schema to xml.
        ///  
        /// The XmlWriter to write the xml to. 
        public void WriteStoreSchema(XmlWriter writer)
        { 
            EDesignUtil.CheckArgumentNull(writer, "writer");
            CheckValidItemCollection();

            // we are going to add this EntityStoreSchemaGenerator namespace at the top of 
            // the file so that when we mark the entitysets with where they came from
            // we don't have to repeat the namespace on each node.  The VS tools use 
            // the source information to give better messages when refreshing the .ssdl from the db 
            // e.g.
            // 
            //    
            //   ...
            //  
            var xmlPrefixToNamespace = new KeyValuePair("store", DesignXmlConstants.EntityStoreSchemaGeneratorNamespace); 
            MetadataItemSerializer.WriteXml(writer, StoreItemCollection, _namespaceName, _errorsLookup, _invalidTypes, _provider, _providerManifestToken, xmlPrefixToNamespace);
        } 


        /// 
        /// Creates an EntityConnection loaded with the providers metadata for the 
        /// 
        /// The provider invariant name. 
        /// The connection for the providers connection. 
        /// An EntityConnection that can query the ConceptualSchemaDefinition for the provider.
        public static EntityConnection CreateStoreSchemaConnection(string providerInvariantName, string connectionString) 
        {
            EDesignUtil.CheckArgumentNull(providerInvariantName, "providerInvariantName");
            EDesignUtil.CheckArgumentNull(connectionString, "connectionString");
 
            DbProviderFactory factory;
            try 
            { 
                factory = DbProviderFactories.GetFactory(providerInvariantName);
            } 
            catch (ArgumentException e)
            {
                throw EDesignUtil.Argument(Strings.EntityClient_InvalidStoreProvider(providerInvariantName), e);
            } 

            DbProviderServices providerServices = DbProviderServices.GetProviderServices(factory); 
 
            DbConnection providerConnection = factory.CreateConnection();
            if (providerConnection == null) 
            {
                throw EDesignUtil.ProviderIncompatible(Strings.ProviderFactoryReturnedNullFactory(providerInvariantName));
            }
            providerConnection.ConnectionString = connectionString; 

            MetadataWorkspace workspace = GetProviderSchemaMetadataWorkspace(providerServices, providerConnection); 
 
            // create the connection with the information we have
            return new EntityConnection(workspace, providerConnection); 
        }

        private static MetadataWorkspace GetProviderSchemaMetadataWorkspace(DbProviderServices providerServices, DbConnection providerConnection)
        { 
            XmlReader csdl = null;
            XmlReader ssdl = null; 
            XmlReader msl = null; 

            try 
            {
                // create the metadata workspace
                MetadataWorkspace workspace = new MetadataWorkspace();
 
                string manifestToken = providerServices.GetProviderManifestToken(providerConnection);
                DbProviderManifest providerManifest = providerServices.GetProviderManifest(manifestToken); 
 
                // create the EdmItemCollection
                IList errors; 
                ssdl = providerManifest.GetInformation(DbProviderManifest.StoreSchemaDefinition);
                string location = Strings.DbProviderServicesInformationLocationPath(providerConnection.GetType().Name, DbProviderManifest.StoreSchemaDefinition);
                List ssdlLocations = new List(1);
                ssdlLocations.Add(location); 
                StoreItemCollection storeItemCollection = new StoreItemCollection(new XmlReader[] { ssdl }, ssdlLocations.AsReadOnly(), out errors);
                ThrowOnError(errors); 
                workspace.RegisterItemCollection(storeItemCollection); 

                csdl = DbProviderServices.GetConceptualSchemaDescription(); 
                location = Strings.DbProviderServicesInformationLocationPath(providerConnection.GetType().Name, DbProviderManifest.ConceptualSchemaDefinition);
                List csdlLocations = new List(1);
                csdlLocations.Add(location);
                EdmItemCollection edmItemCollection = new EdmItemCollection(new XmlReader[] { csdl }, csdlLocations.AsReadOnly(), out errors); 
                ThrowOnError(errors);
                workspace.RegisterItemCollection(edmItemCollection); 
 

                msl = providerManifest.GetInformation(DbProviderManifest.StoreSchemaMapping); 
                location = Strings.DbProviderServicesInformationLocationPath(providerConnection.GetType().Name, DbProviderManifest.StoreSchemaMapping);
                List mslLocations = new List(1);
                mslLocations.Add(location);
                StorageMappingItemCollection mappingItemCollection = new StorageMappingItemCollection(edmItemCollection, 
                                                                         storeItemCollection,
                                                                         new XmlReader[] { msl }, 
                                                                         mslLocations, 
                                                                         out errors);
                ThrowOnError(errors); 
                workspace.RegisterItemCollection(mappingItemCollection);

                // make the views generate here so we can wrap the provider schema problems
                // in a ProviderIncompatibleException 
                ForceViewGeneration(workspace);
                return workspace; 
            } 
            catch (ProviderIncompatibleException)
            { 
                // we don't really want to catch this one, just rethrow it
                throw;
            }
            catch (Exception e) 
            {
                if (EntityUtil.IsCatchableExceptionType(e)) 
                { 
                    throw EDesignUtil.ProviderIncompatible(Strings.ProviderSchemaErrors, e);
                } 

                throw;
            }
            finally 
            {
                if (csdl != null) ((IDisposable)csdl).Dispose(); 
                if (ssdl != null) ((IDisposable)ssdl).Dispose(); 
                if (msl != null) ((IDisposable)msl).Dispose();
            } 
        }

        private static void ForceViewGeneration(MetadataWorkspace workspace)
        { 
            ReadOnlyCollection containers = workspace.GetItems(DataSpace.SSpace);
            Debug.Assert(containers.Count != 0, "no s space containers found"); 
            Debug.Assert(containers[0].BaseEntitySets.Count != 0, "no entity sets in the sspace container"); 
            workspace.GetCqtView(containers[0].BaseEntitySets[0]);
        } 

        private static void ThrowOnError(IList errors)
        {
            if (errors.Count != 0) 
            {
                if (!MetadataHelper.CheckIfAllErrorsAreWarnings(errors)) 
                { 
                    throw EDesignUtil.ProviderIncompatible(Strings.ProviderSchemaErrors, EntityUtil.InvalidSchemaEncountered(Helper.CombineErrorMessage(errors)));
                } 
            }
        }

        private void CheckValidItemCollection() 
        {
            if (_entityContainer == null) 
            { 
                throw EDesignUtil.EntityStoreGeneratorSchemaNotLoaded();
            } 
        }

        internal static bool HasErrorSeverityErrors(IEnumerable errors)
        { 
            foreach (EdmSchemaError error in errors)
            { 
                if (error.Severity == EdmSchemaErrorSeverity.Error) 
                {
                    return true; 
                }
            }
            return false;
        } 

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

        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.CreateMetadataPropertyFromOtherNamespaceXmlAttribute(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorTypeAttributeName, GetSourceNameFromObjectType(key.ObjectType));
            List properties = new List(); 
            properties.Add(property);
            entitySet.AddMetadataProperties(properties);
            entitySet.SetReadOnly();
            return entitySet; 
        }
 
        private string GetSourceNameFromObjectType(DbObjectType dbObjectType) 
        {
            switch(dbObjectType) 
            {
                case DbObjectType.Table:
                    return DesignXmlConstants.TypeValueTables;
                default: 
                    Debug.Assert(dbObjectType == DbObjectType.View, "did you change to a call that could have different types?");
                    return DesignXmlConstants.TypeValueViews; 
            } 
        }
 
        private void CreateEdmFunctions(LoadMethodSessionState session)
        {
            using(FunctionDetailsReader reader = _loader.LoadStoredProcedureDetails(session.Filters))
            { 
                DbObjectKey currentFunction = new DbObjectKey();
                List parameters = new List(); 
                while(reader.Read()) 
                {
                    DbObjectKey rowFunction = reader.CreateDbObjectKey(); 
                    if (rowFunction != currentFunction)
                    {
                        if (!currentFunction.IsEmpty)
                        { 
                            CreateEdmFunction(session, parameters);
                            parameters.Clear(); 
                        } 
                        currentFunction = rowFunction;
                    } 
                    parameters.Add(reader.CreateMemento());
                }

                if (parameters.Count != 0) 
                {
                    CreateEdmFunction(session, parameters); 
                } 

            } 
        }

        private void CreateEdmFunction(LoadMethodSessionState session, List 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 errors = new List();
            if (!row.IsReturnTypeNull)
            { 
                TypeUsage returnType = GetFunctionTypeUsage(session, row.ReturnType);
                if (returnType != null) 
                { 
                    returnParameter = new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue);
                } 
                else
                {
                    isValid = false;
                    errors.Add(new EdmSchemaError( 
                        Strings.UnsupportedFunctionReturnDataType(
                            row.ProcedureName, 
                            row.ReturnType), 
                        (int)ModelBuilderErrorCode.UnsupportedType,
                        EdmSchemaErrorSeverity.Warning)); 
                }
            }

 
            bool caseSensitive = false;
            UniqueIdentifierService uniqueIdentifiers = new UniqueIdentifierService(caseSensitive); 
            List functionParameters = new List(); 
            for (int i = 0; i < parameters.Count && !row.IsParameterNameNull; i++)
            { 
                row.Attach(parameters[i]);
                TypeUsage parameterType = null;
                if(!row.IsParameterTypeNull)
                { 
                    parameterType = GetFunctionTypeUsage(session, row.ParameterType);
                } 
 
                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( 
                        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);
            EdmFunction function = new EdmFunction(functionName,
                _namespaceName,
                DataSpace.SSpace, 
                new EdmFunctionPayload
                { 
                    Schema = row.IsSchemaNull ? null : row.Schema, 
                    StoreFunctionName = functionName != row.ProcedureName ? row.ProcedureName : null,
                    IsAggregate = row.IsIsAggregate, 
                    IsBuiltIn = row.IsBuiltIn,
                    IsNiladic = row.IsNiladic,
                    IsComposable = row.IsComposable,
                    ReturnParameter = returnParameter, 
                    Parameters = functionParameters.ToArray()
                }); 
 

            session.AddErrorsForType(function, errors); 
            if (isValid)
            {
                session.Functions.Add(function);
            } 
            else
            { 
                session.InvalidTypes.Add(function); 
            }
        } 

        private TypeUsage GetFunctionTypeUsage(LoadMethodSessionState session, string dataType)
        {
            PrimitiveType primitiveType; 
            if (session.TryGetStorePrimitiveType(dataType, out primitiveType))
            { 
                TypeUsage usage = TypeUsage.Create(primitiveType, FacetValues.NullFacetValues); 
                return usage;
            } 
            return null;
        }

        private void CreateAssociationTypes(LoadMethodSessionState session) 
        {
            RelationshipDetailsCollection relationships = _loader.LoadRelationships(session.Filters); 
 
            string currentRelationshipId = string.Empty;
            List columns = new List(); 
            foreach (RelationshipDetailsRow row in relationships.Rows)
            {
                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 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 allFkColumnsAreNullable = AreAllFkKeyColumnsNullable(fkEntityType, columns);
            RelationshipMultiplicity pkMultiplicity = allFkColumnsAreNullable ? 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 ( !allFkColumnsAreNullable && 
                 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, DataSpace.SSpace);
            type.AddMember(pkEnd); 
            type.AddMember(fkEnd);

            List errors = new List();
            bool isValid = CreateReferentialConstraint(session, 
                        type,
                        pkEnd, 
                        fkEnd, 
                        columns,
                        errors); 


            string errorMessage;
            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 toPropertyOfAddedAssc 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(toPropertyOfAddedAssc.DeclaringType) && toProperty.Equals(toPropertyOfAddedAssc))
                        { 
                            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 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 static bool AreRelationshipColumnsTheTypesEntireKey(
            EntityType entity, 
            List columns,
            Func getColumnName)
        {
            if (entity.KeyMembers.Count != columns.Count) 
            {
                // to be the entire key, 
                // must have the same number of columns 
                return false;
            } 

            foreach (RelationshipDetailsRow row in columns)
            {
                if (!entity.KeyMembers.Contains(getColumnName(row))) 
                {
                    // not a key 
                    return false; 
                }
            } 
            return true;
        }

        private static bool AreAllFkKeyColumnsNullable( 
            EntityType entity,
            List columns) 
        { 
            foreach (RelationshipDetailsRow row in columns)
            { 
                EdmProperty property;
                if (entity.Properties.TryGetValue(row.FKColumn, false, out property))
                {
                    if (!property.Nullable) 
                    {
                        return false; 
                    } 
                }
                else 
                {
                    Debug.Fail("Why didn't we find the column?");
                    return false;
                } 
            }
            return true; 
        } 

 
        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 bool CreateReferentialConstraint(LoadMethodSessionState session, 
            AssociationType association,
            AssociationEndMember pkEnd, 
            AssociationEndMember fkEnd,
            List columns,
            List 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;
        } 

        static internal bool IsFkPartiallyContainedInPK(AssociationType association, out string errorMessage) 
        { 
            ReferentialConstraint constraint = association.ReferentialConstraints[0];
            EntityType toType = (EntityType)constraint.ToProperties[0].DeclaringType; 

            bool toPropertiesAreFullyContainedInPk = true;
            bool toPropertiesContainedAtLeastOnePK = false;
 
            foreach (EdmProperty edmProperty in constraint.ToProperties)
            { 
                // check if there is at least one to property is not primary key 
                toPropertiesAreFullyContainedInPk &= toType.KeyMembers.Contains(edmProperty);
                // check if there is one to property is primary key 
                toPropertiesContainedAtLeastOnePK |= toType.KeyMembers.Contains(edmProperty);
            }
            if (!toPropertiesAreFullyContainedInPk && toPropertiesContainedAtLeastOnePK)
            { 
                string foreignKeys = MembersToCommaSeparatedString((System.Collections.IEnumerable)constraint.ToProperties);
                string primaryKeys = MembersToCommaSeparatedString((System.Collections.IEnumerable)toType.KeyMembers); 
                errorMessage = Strings.UnsupportedForeignKeyPattern(association.Name, foreignKeys, primaryKeys, toType.Name); 
                return true;
            } 
            errorMessage = "";
            return false;
        }
 
        private static string MembersToCommaSeparatedString(System.Collections.IEnumerable members)
        { 
            StringBuilder builder = new StringBuilder(); 
            builder.Append("{");
            StringUtil.ToCommaSeparatedString(builder, members); 
            builder.Append("}");
            return builder.ToString();
        }
 
        private void CreateViewEntityTypes(LoadMethodSessionState session)
        { 
            TableDetailsCollection viewDetails = _loader.LoadViewDetails(session.Filters); 
            CreateEntityTypes(session, viewDetails, DbObjectType.View);
        } 

        private void CreateTableEntityTypes(LoadMethodSessionState session)
        {
            TableDetailsCollection tableDetails = _loader.LoadTableDetails(session.Filters); 
            CreateEntityTypes(session, tableDetails, DbObjectType.Table);
        } 
 
        private void CreateEntityTypes(LoadMethodSessionState session, TableDetailsCollection details, DbObjectType objectType)
        { 

            DbObjectKey currentKey = new DbObjectKey();
            List singleTableColumns = new List();
            List primaryKeys = new List(); 
            foreach (TableDetailsRow row in details.Rows)
            { 
                DbObjectKey rowKey = CreateDbObjectKey(row, objectType); 
                if (rowKey != currentKey)
                { 
                    if (singleTableColumns.Count != 0)
                    {
                        CreateEntityType(
                            session, 
                            singleTableColumns,
                            primaryKeys, 
                            objectType, 
                            null);
 
                        singleTableColumns.Clear();
                        primaryKeys.Clear();
                    }
                    currentKey = rowKey; 
                }
 
                singleTableColumns.Add(row); 
                if (row.IsPrimaryKey)
                { 
                    primaryKeys.Add(row.ColumnName);
                }
            }
 
            // pick up the last one
            if (singleTableColumns.Count != 0) 
            { 
                CreateEntityType(
                            session, 
                            singleTableColumns,
                            primaryKeys,
                            objectType,
                            null); 

            } 
        } 

        private void CreateEntityType(LoadMethodSessionState session, 
            IList columns,
            ICollection primaryKeys,
            DbObjectType objectType,
            List errors) 
        {
            Debug.Assert(columns.Count != 0, "Trying to create an EntityType with 0 properties"); 
 
            //
            // Handle Tables without explicit declaration of keys 
            //
            DbObjectKey tableKey = CreateDbObjectKey(columns[0], objectType);
            EntityCreationStatus status = EntityCreationStatus.Normal;
            if (errors == null) 
            {
                errors = new List(); 
            } 

            if (primaryKeys.Count == 0) 
            {
                List pKeys = new List(columns.Count);
                session.AddTableWithoutKey(tableKey);
                if (InferKeyColumns(session, columns, pKeys, tableKey, ref primaryKeys)) 
                {
                    errors.Add(new EdmSchemaError( 
                        Strings.NoPrimaryKeyDefined(tableKey), 
                                    (int)ModelBuilderErrorCode.NoPrimaryKeyDefined,
                                     EdmSchemaErrorSeverity.Warning)); 
                    status = EntityCreationStatus.ReadOnly;
                }
                else
                { 
                    errors.Add(new EdmSchemaError(
                        Strings.CannotCreateEntityWithNoPrimaryKeyDefined(tableKey), 
                                        (int)ModelBuilderErrorCode.CannotCreateEntityWithoutPrimaryKey, 
                                        EdmSchemaErrorSeverity.Warning));
                    status = EntityCreationStatus.Invalid; 
                }
            }

            Debug.Assert(primaryKeys == null || primaryKeys.Count > 0,"There must be at least one key columns at this point in time"); 

            List members = new List(); 
            List excludedKeyColumns = new List(); 
            foreach (TableDetailsRow row in columns)
            { 
                bool isPartOfKey = primaryKeys != null && primaryKeys.Contains(row.ColumnName);
                PrimitiveType primitiveType;
                if ( row.IsDataTypeNull() || !session.TryGetStorePrimitiveType(row.DataType, out primitiveType))
                { 
                    string message;
                    if(!row.IsDataTypeNull()) 
                    { 
                        message = Strings.UnsupportedDataType(row.DataType, row.GetMostQualifiedTableName(), row.ColumnName);
                    } 
                    else
                    {
                        message = Strings.UnsupportedDataTypeUnknownType(row.ColumnName, row.GetMostQualifiedTableName());
                    } 

                    errors.Add(new EdmSchemaError(message, 
                        (int)ModelBuilderErrorCode.UnsupportedType, EdmSchemaErrorSeverity.Warning)); 

                    if(isPartOfKey) 
                    {
                        excludedKeyColumns.Add(row.ColumnName);
                    }
                    continue; 
                }
 
                if (isPartOfKey && !Helper.IsValidKeyType(primitiveType.PrimitiveTypeKind)) 
                {
                    // make it a read-only table by calling this method recursivly with no keys 
                    List priorErrors = new List();
                    priorErrors.Add(new EdmSchemaError(Strings.InvalidTypeForPrimaryKey(row.GetMostQualifiedTableName(),
                        row.ColumnName,
                        row.DataType), 
                        (int)ModelBuilderErrorCode.InvalidKeyTypeFound,
                        EdmSchemaErrorSeverity.Warning)); 
 

                    string[] keyColumns = new string[0]; 
                    CreateEntityType(session, columns, keyColumns, objectType, priorErrors);
                    return;
                }
 
                Dictionary facets = primitiveType.GetAssociatedFacetDescriptions().ToDictionary(fd => fd.FacetName, fd => fd.DefaultValueFacet);
                facets[DbProviderManifest.NullableFacetName] = Facet.Create(facets[DbProviderManifest.NullableFacetName].Description, row.IsNullable); 
 
                if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Decimal)
                { 
                    Facet precision;
                    if (facets.TryGetValue(DbProviderManifest.PrecisionFacetName, out precision))
                    {
                        if (!row.IsPrecisionNull() && !precision.Description.IsConstant) 
                        {
                            if (row.Precision < precision.Description.MinValue || row.Precision > precision.Description.MaxValue) 
                            { 
                                DbObjectKey key = CreateDbObjectKey(row, objectType);
                                errors.Add(new EdmSchemaError( 
                                    Strings.ColumnFacetValueOutOfRange(
                                        DbProviderManifest.PrecisionFacetName,
                                        row.Precision,
                                        precision.Description.MinValue, 
                                        precision.Description.MaxValue,
                                        row.ColumnName, 
                                        key), 
                                    (int)ModelBuilderErrorCode.FacetValueOutOfRange,
                                    EdmSchemaErrorSeverity.Warning)); 
                                if (isPartOfKey)
                                {
                                    excludedKeyColumns.Add(row.ColumnName);
                                } 
                                continue;
                            } 
                            facets[precision.Name] = Facet.Create(precision.Description, (byte)row.Precision); 
                        }
                    } 
                    Facet scale;
                    if (facets.TryGetValue(DbProviderManifest.ScaleFacetName, out scale))
                    {
                        if (!row.IsScaleNull() && !scale.Description.IsConstant) 
                        {
                            if (row.Scale < scale.Description.MinValue || row.Scale > scale.Description.MaxValue) 
                            { 
                                DbObjectKey key = CreateDbObjectKey(row, objectType);
                                errors.Add(new EdmSchemaError( 
                                    Strings.ColumnFacetValueOutOfRange(
                                        DbProviderManifest.ScaleFacetName,
                                        row.Scale,
                                        scale.Description.MinValue, 
                                        scale.Description.MaxValue,
                                        row.ColumnName, 
                                        key), 
                                    (int)ModelBuilderErrorCode.FacetValueOutOfRange,
                                    EdmSchemaErrorSeverity.Warning)); 
                                if (isPartOfKey)
                                {
                                    excludedKeyColumns.Add(row.ColumnName);
                                } 
                                continue;
                            } 
                            facets[scale.Name] = Facet.Create(scale.Description, (byte)row.Scale); 
                        }
                    } 
                }
                else if ((primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.DateTime) || (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Time)
                        || (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.DateTimeOffset))
                { 
                    Facet datetimePrecision;
                    if (facets.TryGetValue(DbProviderManifest.PrecisionFacetName, out datetimePrecision)) 
                    { 
                        if (!row.IsDateTimePrecisionNull() && !datetimePrecision.Description.IsConstant)
                        { 
                            if (row.DateTimePrecision < datetimePrecision.Description.MinValue || row.DateTimePrecision > datetimePrecision.Description.MaxValue)
                            {
                                DbObjectKey key = CreateDbObjectKey(row, objectType);
                                errors.Add(new EdmSchemaError( 
                                    Strings.ColumnFacetValueOutOfRange(
                                        DbProviderManifest.PrecisionFacetName, 
                                        row.DateTimePrecision, 
                                        datetimePrecision.Description.MinValue,
                                        datetimePrecision.Description.MaxValue, 
                                        row.ColumnName,
                                        key),
                                    (int)ModelBuilderErrorCode.FacetValueOutOfRange,
                                    EdmSchemaErrorSeverity.Warning)); 
                                if (isPartOfKey)
                                { 
                                    excludedKeyColumns.Add(row.ColumnName); 
                                }
                                continue; 
                            }
                            facets[datetimePrecision.Name] = Facet.Create(datetimePrecision.Description, (byte)row.DateTimePrecision);
                        }
                    } 
                }
                else if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String || 
                       primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary) 
                {
                    Facet maxLength; 
                    if (facets.TryGetValue(DbProviderManifest.MaxLengthFacetName, out maxLength))
                    {
                        if (!row.IsMaximumLengthNull() && !maxLength.Description.IsConstant)
                        { 
                            if (row.MaximumLength < maxLength.Description.MinValue || row.MaximumLength > maxLength.Description.MaxValue)
                            { 
                                DbObjectKey key = CreateDbObjectKey(row, objectType); 
                                errors.Add(new EdmSchemaError(
                                    Strings.ColumnFacetValueOutOfRange( 
                                        DbProviderManifest.MaxLengthFacetName,
                                        row.MaximumLength,
                                        maxLength.Description.MinValue,
                                        maxLength.Description.MaxValue, 
                                        row.ColumnName,
                                        key), 
                                    (int)ModelBuilderErrorCode.FacetValueOutOfRange, 
                                    EdmSchemaErrorSeverity.Warning));
                                if (isPartOfKey) 
                                {
                                    excludedKeyColumns.Add(row.ColumnName);
                                }
                                continue; 
                            }
                            facets[maxLength.Name] = Facet.Create(maxLength.Description, row.MaximumLength); 
                        } 
                    }
                } 

                if (!row.IsIsIdentityNull() && row.IsIdentity)
                {
                    Facet facet = Facet.Create(System.Data.Metadata.Edm.Converter.StoreGeneratedPatternFacet, StoreGeneratedPattern.Identity); 
                    facets.Add(facet.Name, facet);
                } 
                else if (!row.IsIsServerGeneratedNull() && row.IsServerGenerated) 
                {
                    Facet facet = Facet.Create(System.Data.Metadata.Edm.Converter.StoreGeneratedPatternFacet, StoreGeneratedPattern.Computed); 
                    facets.Add(facet.Name, facet);
                }

 
                members.Add(new EdmProperty(row.ColumnName, TypeUsage.Create(primitiveType, facets.Values)));
            } 
 
            if (excludedKeyColumns.Count > 0)
            { 
                // see if we have any keys left
                if (primaryKeys != null && excludedKeyColumns.Count < primaryKeys.Count)
                {
                    List newKeys = new List(); 
                    foreach (string key in primaryKeys)
                    { 
                        if (!excludedKeyColumns.Contains(key)) 
                        {
                            newKeys.Add(key); 
                        }
                    }
                    primaryKeys = newKeys;
                    status = EntityCreationStatus.ReadOnly; 
                }
                else 
                { 
                    primaryKeys = null;
                    status = EntityCreationStatus.Invalid; 
                }

                foreach (string columnName in excludedKeyColumns)
                { 
                    if (status == EntityCreationStatus.ReadOnly)
                    { 
                        errors.Add(new EdmSchemaError( 
                            Strings.ExcludedColumnWasAKeyColumnEntityIsReadOnly(columnName, columns[0].GetMostQualifiedTableName()),
                            (int)ModelBuilderErrorCode.ExcludedColumnWasAKeyColumn, 
                            EdmSchemaErrorSeverity.Warning));
                    }
                    else
                    { 
                        Debug.Assert(status == EntityCreationStatus.Invalid, "Did we change some code above to make it possible to be something different?");
                        errors.Add(new EdmSchemaError( 
                            Strings.ExcludedColumnWasAKeyColumnEntityIsInvalid(columnName, columns[0].GetMostQualifiedTableName()), 
                            (int)ModelBuilderErrorCode.ExcludedColumnWasAKeyColumn,
                            EdmSchemaErrorSeverity.Warning)); 
                    }
                }
            }
 
            string typeName = session.UsedTypeNames.AdjustIdentifier(columns[0].TableName);
            EntityType entityType = new EntityType(typeName, _namespaceName, DataSpace.SSpace, 
                primaryKeys, 
                members);
 
            switch (status)
            {
                case EntityCreationStatus.Normal:
                    session.AddEntity(tableKey, entityType); 
                    break;
                case EntityCreationStatus.ReadOnly: 
                    session.AddEntity(tableKey, entityType); 
                    session.ReadOnlyEntities.Add(entityType);
                    break; 
                default:
                    Debug.Assert(status == EntityCreationStatus.Invalid, "did you add a new value?");
                    session.InvalidTypes.Add(entityType);
                    break; 
            }
 
            entityType.SetReadOnly(); 
            session.AddErrorsForType(entityType, errors);
        } 

        private static bool InferKeyColumns(LoadMethodSessionState session, IList columns, List pKeys, DbObjectKey tableKey, ref ICollection primaryKeys)
        {
            for (int i = 0; i < columns.Count; i++) 
            {
                if (!columns[i].IsNullable) 
                { 
                    PrimitiveType primitiveType;
                    if (session.TryGetStorePrimitiveType(columns[i].DataType, out primitiveType) && 
                        Helper.IsValidKeyType(primitiveType.PrimitiveTypeKind) )
                    {
                        pKeys.Add(columns[i].ColumnName);
                    } 
                }
            } 
 
            // if there are valid key column candidates, make them the new key columns
            if (pKeys.Count > 0) 
            {
                primaryKeys = pKeys;
            }
            else 
            {
                primaryKeys = null; 
            } 

            return primaryKeys != null; 
        }

        private DbObjectKey CreateDbObjectKey(TableDetailsRow row, DbObjectType objectType)
        { 
            TableDetailsCollection table = row.Table;
            return new DbObjectKey(row[table.CatalogColumn], 
                row[table.SchemaColumn], 
                row[table.TableNameColumn], objectType);
        } 

        /// 
        /// Populates DefiningQuery attribute of RO view entities
        ///  
        /// 
        ///  
        ///  
        private void FixupKeylessEntitySets(EntityContainer entityContainer, LoadMethodSessionState session)
        { 
            // if there are views to process
            if (session.ReadOnlyEntities.Count > 0)
            {
                // 
                // create 'bogus' metadataworkspace
                // 
                MetadataWorkspace metadataWorkspace = CreateMetadataWorkspace(entityContainer, session); 

                // 
                // For all tables/views that we could infer valid keys, update DefiningQuery with
                // provider specific ReadOnly view SQL
                //
                foreach (EntityType entityType in session.ReadOnlyEntities) 
                {
                    EntitySet entitySet = session.EntityTypeToSet[entityType]; 
                    DbObjectKey key = session.GetKey(entityType); 

                    // add properties that make it possible for the designer to track back these 
                    // types to their source db objects
                    List properties = new List();
                    if (key.Schema != null)
                    { 
                        properties.Add(System.Data.EntityModel.SchemaObjectModel.SchemaElement.CreateMetadataPropertyFromOtherNamespaceXmlAttribute(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorSchemaAttributeName, key.Schema));
                    } 
                    properties.Add(System.Data.EntityModel.SchemaObjectModel.SchemaElement.CreateMetadataPropertyFromOtherNamespaceXmlAttribute(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorNameAttributeName, key.TableName)); 
                    entitySet.AddMetadataProperties(properties);
 
                    FixupViewEntitySetDefiningQuery(entitySet, metadataWorkspace);
                }
            }
        } 

        ///  
        /// Creates 'transient' metadataworkspace based on store schema (EntityContainer) and trivial C-S mapping 
        /// 
        ///  
        /// 
        /// 
        private MetadataWorkspace CreateMetadataWorkspace(EntityContainer entityContainer, LoadMethodSessionState session)
        { 
            MetadataWorkspace metadataWorkspace = new MetadataWorkspace();
 
            EntityModelSchemaGenerator modelGen = new EntityModelSchemaGenerator(entityContainer); 
            modelGen.GenerateMetadata();
 
            // register edmitemcollection
            metadataWorkspace.RegisterItemCollection(modelGen.EdmItemCollection);

            // register StoreItemCollection 
            metadataWorkspace.RegisterItemCollection(session.ItemCollection);
 
            // register mapping 
            using (MemoryStream memStream = new MemoryStream())
            { 
                using (XmlWriter xmlWriter = XmlWriter.Create(memStream))
                {
                    modelGen.WriteStorageMapping(xmlWriter);
                    xmlWriter.Close(); 
                }
 
                memStream.Seek(0, SeekOrigin.Begin); 

                using (XmlReader xmlReader = XmlReader.Create(memStream)) 
                {
                    List xmlReaders = new List();
                    xmlReaders.Add(xmlReader);
                    metadataWorkspace.RegisterItemCollection(new StorageMappingItemCollection(modelGen.EdmItemCollection, 
                                                                                              session.ItemCollection,
                                                                                              xmlReaders)); 
                } 
            }
 
            return metadataWorkspace;
        }

        ///  
        /// Generates provider specific, read only SQL and updates entitySet DefiningQuery
        ///  
        ///  
        /// 
        private void FixupViewEntitySetDefiningQuery(EntitySet entitySet, MetadataWorkspace metadataWorkspace) 
        {
            DbQueryCommandTree dbCommandTree = new DbQueryCommandTree(metadataWorkspace, DataSpace.SSpace);
            DbExpressionBinding inputBinding = dbCommandTree.CreateExpressionBinding(dbCommandTree.CreateScanExpression(entitySet), entitySet.Name);
            List> projectList = new List>(entitySet.ElementType.Members.Count); 
            foreach (EdmMember member in entitySet.ElementType.Members)
            { 
                Debug.Assert(member.BuiltInTypeKind == BuiltInTypeKind.EdmProperty, "Every member must be a edmproperty"); 
                EdmProperty propertyInfo = (EdmProperty)member;
                projectList.Add(new KeyValuePair(member.Name, 
                                                                       dbCommandTree.CreatePropertyExpression(propertyInfo,
                                                                                                              inputBinding.Variable)));
            }
            dbCommandTree.Query = dbCommandTree.CreateProjectExpression(inputBinding, 
                                                                        dbCommandTree.CreateNewRowExpression(projectList));
            dbCommandTree.Validate(); 
 
            //
            // get provider SQL and set entitySet DefiningQuery 
            //
            entitySet.DefiningQuery = (DbProviderServices.GetProviderServices(_loader.EntityConnection.StoreProviderFactory)
                                                            .CreateCommandDefinition(dbCommandTree))
                                                                .CreateCommand().CommandText; 

            Debug.Assert(!String.IsNullOrEmpty(entitySet.DefiningQuery), "DefiningQuery must not be null or empty"); 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK