EntityStoreSchemaGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntityDesign / Design / System / Data / Entity / Design / EntityStoreSchemaGenerator.cs / 1305376 / 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.Data.Common.CommandTrees.ExpressionBuilder;
using System.Text; 
using System.Linq; 
using Microsoft.Build.Utilities;
 
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; 
        private Version _targetEntityFrameworkVersion;
 
        /// 
        /// 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 = 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
        ///  
        [CLSCompliant(false)] 
        public StoreItemCollection StoreItemCollection
        { 
            get
            {
                return _storeItemCollection;
            } 
        }
 
        ///  
        /// Indicates whether the given storage model will be used to produce an entity model with foreign keys.
        ///  
        public bool GenerateForeignKeyProperties
        {
            get;
            set; 
        }
 
        ///  
        /// 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 DoGenerateStoreMetadata(filters, EntityFrameworkVersions.Latest);
        } 
 
        /// 
        /// 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"); 
            return DoGenerateStoreMetadata(filters, EntityFrameworkVersions.Latest); 
        }
                ///  
        /// Creates a Metadata schema from the DbSchemaLoader that was passed in
        /// 
        /// The filters to be applied during generation.
        /// The filters to be applied during generation. 
        /// The new metadata for the schema that was loaded
        public IList GenerateStoreMetadata(IEnumerable filters, Version targetEntityFrameworkVersion) 
        { 
            EDesignUtil.CheckArgumentNull(filters, "filters");
            EDesignUtil.CheckTargetEntityFrameworkVersionArgument(targetEntityFrameworkVersion, "targetEntityFrameworkVersion"); 


            // we are not going to actually use targetFrameworkMoniker at this time, but
            // we want the option to use it in the future if we change the 
            // the ssdl schema
            return DoGenerateStoreMetadata(filters, targetEntityFrameworkVersion); 
        } 

        private IList DoGenerateStoreMetadata(IEnumerable filters, Version targetEntityFrameworkVersion) 
        {

            if (_entityContainer != null)
            { 
                _entityContainer = null;
                _storeItemCollection = null; 
                _errorsLookup = null; 
                _invalidTypes = null;
            } 

            _targetEntityFrameworkVersion = targetEntityFrameworkVersion;
            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), _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 (MetadataUtil.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, _targetEntityFrameworkVersion, 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 = MetadataUtil.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 (MetadataUtil.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 (!MetadataUtil.CheckIfAllErrorsAreWarnings(errors)) 
                {
                    throw EDesignUtil.ProviderIncompatible(Strings.ProviderSchemaErrors, EntityUtil.InvalidSchemaEncountered(MetadataUtil.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.CreateMetadataPropertyFromOtherNamespaceXmlArtifact(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 someFkColmnsAreNullable; 
            if (_targetEntityFrameworkVersion == EntityFrameworkVersions.Version1)
            { 
                someFkColmnsAreNullable = AreAllFkKeyColumnsNullable(fkEntityType, columns); 
            }
            else 
            {
                someFkColmnsAreNullable = AreAnyFkKeyColumnsNullable(fkEntityType, columns);
            }
 
            RelationshipMultiplicity pkMultiplicity = someFkColmnsAreNullable ? RelationshipMultiplicity.ZeroOrOne : RelationshipMultiplicity.One;
            //Get the Delete Action for the end and set it. 
            //The only DeleteAction we support is Cascade, ignor all others for now. 
            OperationAction onDeleteAction = OperationAction.None;
            if (firstRow.RelationshipIsCascadeDelete) 
            {
                onDeleteAction = OperationAction.Cascade;
            }
 
            AssociationEndMember pkEnd = CreateAssociationEnd( session,
                        pkEntityType, 
                        pkMultiplicity, 
                        usedEndNames, onDeleteAction);
 
            RelationshipMultiplicity fkMultiplicity = RelationshipMultiplicity.Many;

            if ( !someFkColmnsAreNullable &&
                 AreRelationshipColumnsTheTypesEntireKey(fkEntityType, columns, r => r.FKColumn)) 
            {
                // both the pk and fk side columns are the keys of their types 
                // so this is a 1 to one relationship 
                fkMultiplicity = RelationshipMultiplicity.ZeroOrOne;
            } 

            AssociationEndMember fkEnd = CreateAssociationEnd(session,
                        fkEntityType,
                        fkMultiplicity, 
                        usedEndNames, OperationAction.None);
 
 
            // create the type
            string typeName = session.UsedTypeNames.AdjustIdentifier(firstRow.RelationshipName); 
            AssociationType type = new AssociationType(typeName,
                _namespaceName, false, DataSpace.SSpace);
            type.AddMember(pkEnd);
            type.AddMember(fkEnd); 

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

            string errorMessage; 
 
            // We can skip most validation checks if the FKs are directly surfaced (since we can produce valid mappings in these cases).
            if (!this.GenerateForeignKeyProperties) 
            {
                if (IsFkPartiallyContainedInPK(type, out errorMessage))
                {
                    errors.Add(new EdmSchemaError( 
                        errorMessage,
                        (int)ModelBuilderErrorCode.UnsupportedForeinKeyPattern, 
                        EdmSchemaErrorSeverity.Warning)); 
                    isValid = false;
                } 

                if (isValid)
                {
                    //Now check if any FK (which could also be a PK) is shared among multiple Associations (ie shared via foreign key constraint). 
                    // To do this we check if the Association Type being generated has any dependent property which is also a dependent in one of the association typed already added.
                    //If so, we keep one Association and throw the rest away. 
 
                    foreach (var toPropertyOfAddedAssociation in session.AssociationTypes.SelectMany(t => t.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties)))
                    { 
                        foreach (var toProperty in type.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties))
                        {
                            if (toProperty.DeclaringType.Equals(toPropertyOfAddedAssociation.DeclaringType) && toProperty.Equals(toPropertyOfAddedAssociation))
                            { 
                                errors.Add(new EdmSchemaError(
                                    Strings.SharedForeignKey(type.Name, toProperty, toProperty.DeclaringType), 
                                    (int)ModelBuilderErrorCode.SharedForeignKey, 
                                    EdmSchemaErrorSeverity.Warning));
 
                                isValid = false;
                                break;
                            }
                        } 

                        if (!isValid) 
                        { 
                            break;
                        } 
                    }
                }
            }
 
            if (isValid)
            { 
                session.AssociationTypes.Add(type); 
            }
            else 
            {
                session.InvalidTypes.Add(type);
                session.RelationshipEndTypeLookup.Remove(pkEnd);
                session.RelationshipEndTypeLookup.Remove(fkEnd); 
            }
 
 
            type.SetReadOnly();
            session.AddErrorsForType(type, errors); 
        }

        private 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 AreAnyFkKeyColumnsNullable(
            EntityType entity, 
            List columns)
        { 
            foreach (RelationshipDetailsRow row in columns) 
            {
                EdmProperty property; 
                if (entity.Properties.TryGetValue(row.FKColumn, false, out property))
                {
                    if (property.Nullable)
                    { 
                        return true;
                    } 
                } 
                else
                { 
                    Debug.Fail("Why didn't we find the column?");
                    return false;
                }
            } 
            return false;
        } 
 
        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 = MetadataUtil.MembersToCommaSeparatedString((System.Collections.IEnumerable)constraint.ToProperties);
                string primaryKeys = MetadataUtil.MembersToCommaSeparatedString((System.Collections.IEnumerable)toType.KeyMembers); 
                errorMessage = Strings.UnsupportedForeignKeyPattern(association.Name, foreignKeys, primaryKeys, toType.Name);
                return true;
            }
            errorMessage = ""; 
            return false;
        } 
 
        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 && !MetadataUtil.IsValidKeyType(_targetEntityFrameworkVersion, 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 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) &&
                        MetadataUtil.IsValidKeyType(_targetEntityFrameworkVersion, 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);

                if (null == metadataWorkspace)
                { 
                    // failed to create bogus metadataworkspace
                    return; 
                } 

                // 
                // 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.CreateMetadataPropertyFromOtherNamespaceXmlArtifact(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorSchemaAttributeName, key.Schema));
                    } 
                    properties.Add(System.Data.EntityModel.SchemaObjectModel.SchemaElement.CreateMetadataPropertyFromOtherNamespaceXmlArtifact(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.GenerateForeignKeyProperties = this.GenerateForeignKeyProperties;
 
            IEnumerable errors = modelGen.GenerateMetadata();

            if (EntityStoreSchemaGenerator.HasErrorSeverityErrors(errors))
            { 
                // this is a 'transient' metadataworkspace
                // no errors from this metadataworkspace should be shown to the user 
                return null; 
            }
 
            // 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) 
        {
            DbExpressionBinding inputBinding = DbExpressionBuilder.BindAs(DbExpressionBuilder.Scan(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,
                                                                       DbExpressionBuilder.Property(inputBinding.Variable, propertyInfo))); 
            }
            DbExpression query = inputBinding.Project(DbExpressionBuilder.NewRow(projectList));
            DbQueryCommandTree dbCommandTree = new DbQueryCommandTree(metadataWorkspace, DataSpace.SSpace, query);
 
            //
            // 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