Example #1
0
        public override List <string> BuildSchema(string metadataContent)
        {
            var result = new List <string>();

#if no
            try {
                var modelDefinition = new ModelDefinition()
                {
                    MetaData = metadataContent,
                    Kind     = "OData"
                };

                var modelSchema = new ModelSchema();

                var builder = new ODataModelBuilder();
                builder.ModelDefinition = modelDefinition;
                builder.ModelSchema     = modelSchema;
                result = builder.Build();

                // https://github.com/OData/odata.net/blob/master/src/CodeGen/ODataT4CodeGenerator.ttinclude
                this.EdmModel        = builder.EdmModel;
                this.ModelSchema     = modelSchema;
                this.ModelDefinition = modelDefinition;
            } catch (Exception error) {
                result.Add(error.ToString());
            }
#endif
            return(result);
        }
Example #2
0
        public override ModelSchema GetModelSchema(MetaModelBuilder metaModelBuilder, ModelErrors errors)
        {
            var result = this.ModelSchema;

            if (result is null)
            {
                if (this._EdmxModel != null)
                {
                    var builder = new EdmxModelSchemaBuilder();
                    result = new ModelSchema();
                    builder.Build(this._EdmxModel, result, metaModelBuilder, errors);
#warning result.Freeze();
                    this.ModelSchema = result;
                }
            }
            return(result);
        }
Example #3
0
        public ModelScalarType BuildScalarType(EdmxModel edmxModel, ModelSchema modelSchema, CsdlScalarTypeModel scalarTypeModel, MetaModelBuilder metaModelBuilder, ModelErrors errors)
        {
            if (string.Equals(scalarTypeModel.Namespace, "Edm", StringComparison.Ordinal))
            {
                return(null);
            }
            //
#warning  BuildScalarType - when does this happen?
            var             name     = scalarTypeModel.Name;
            var             fullName = scalarTypeModel.FullName;
            ModelScalarType result   = new ModelScalarType {
                Name         = name,
                ExternalName = fullName
            };
            modelSchema.ScalarTypes.Add(result);
            return(result);
        }
Example #4
0
        public void BuildAssociation(EdmxModel edmxModel, ModelSchema modelSchema, CsdlAssociationModel association, MetaModelBuilder metaModelBuilder, ModelErrors errors)
        {
            foreach (var associationEnd in association.AssociationEnd)
            {
                if (associationEnd.TypeModel is null)
                {
                    if (!(associationEnd.TypeName is null))
                    {
                        errors.AddErrorOrThrow($"{associationEnd.TypeName} not found.", $"{association.FullName} - {associationEnd.FullName}");
                    }
                    continue;
                }
                //associationEnd.GetMultiplicity()
                //var roleName = associationEnd.RoleName;
                //associationEnd.TypeModel
            }
            var lstOneOptional = association.AssociationEnd.Where(end => end.GetMultiplicity() == MultiplicityKind.OneOptional).ToList();
            var lstOne         = association.AssociationEnd.Where(end => end.GetMultiplicity() == MultiplicityKind.One).ToList();
            var lstMultiple    = association.AssociationEnd.Where(end => end.GetMultiplicity() == MultiplicityKind.Multiple).ToList();

            if ((lstOneOptional.Count == 1) && (lstMultiple.Count == 1))
            {
                var masterEnd          = lstOneOptional[0];
                var foreignEnd         = lstMultiple[0];
                var lstMasterProperty  = masterEnd.TypeModel.NavigationProperty.Where(np => np.FromRoleName == masterEnd.RoleName).ToList();
                var lstForeignProperty = foreignEnd.TypeModel.NavigationProperty.Where(np => np.FromRoleName == foreignEnd.RoleName).ToList();
                if ((lstMasterProperty.Count == 1) && (lstForeignProperty.Count == 1))
                {
                    //modelSchema.ComplexTypes.FindByKey2(lstMasterProperty[0])
                    //modelSchema.ComplexTypes.FindByKey2(lstMasterProperty[0].TypeModel.Nam)

                    var result = metaModelBuilder.CreateModelRelation(
                        association.Name,
                        association.FullName,
                        lstMasterProperty[0].ToRoleModel.TypeName,
                        lstMasterProperty[0].Name,
                        lstForeignProperty[0].ToRoleModel.TypeName,
                        lstForeignProperty[0].Name
                        );
                    modelSchema.Relations.Add(result);
                }
            }
        }
        // GET: /<controller>/
        public async Task <IActionResult> Index()
        {
            AuthenticationResult result     = null;
            List <ModelSchema>   schemaList = new List <ModelSchema>();

            try
            {
                // Because we signed-in already in the WebApp, the userObjectId is known
                string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;

                // Using ADAL.Net, get a bearer token to access the MRSDistComp Web APIs
                AuthenticationContext authContext = new AuthenticationContext(AzureAdOptions.Settings.CentralRegistryAuthority, new NaiveSessionCache(userObjectID, HttpContext.Session));
                ClientCredential      credential  = new ClientCredential(AzureAdOptions.Settings.ClientId, AzureAdOptions.Settings.ClientSecret);
                result = await authContext.AcquireTokenAsync(AzureAdOptions.Settings.CentralRegistryResourceAppId, credential);


                // Retrieve the schemas list.
                HttpClient         client  = new HttpClient();
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, AzureAdOptions.Settings.CentralRegistryBaseAddress + "/api/GetSchemas");
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
                HttpContent content = new StringContent(JsonConvert.SerializeObject(new { schemaname = string.Empty }),
                                                        System.Text.Encoding.UTF8,
                                                        "application/json");
                request.Content = content;

                HttpResponseMessage response = await client.SendAsync(request);

                // Return the schemas' in the view.
                if (response.IsSuccessStatusCode)
                {
                    List <Dictionary <String, String> > responseElements = new List <Dictionary <String, String> >();
                    JsonSerializerSettings settings = new JsonSerializerSettings();
                    String responseString           = await response.Content.ReadAsStringAsync();

                    JObject responseJObject = JObject.Parse(responseString);

                    // This is based on the Web API JSON. List of lists of the Result.
                    IList <JToken> rows = responseJObject["outputParameters"]["Result"].Children().ToList();

                    // serialize JSON results into .NET objects
                    foreach (JToken row in rows)
                    {
                        foreach (JToken column in row)
                        {
                            ModelSchema schema = new ModelSchema();
                            schema.Name        = column[1].ToString();
                            schema.Description = column[2].ToString();
                            schema.Version     = column[3].ToString();
                            schema.SchemaJSON  = column[4].ToString();
                            schemaList.Add(schema);
                        }
                    }

                    return(View(schemaList));
                }
                else
                {
                    //
                    // If the call failed with access denied, then drop the current access token from the cache,
                    //     and show the user an error indicating they might need to sign-in again.
                    //
                    if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                    {
                        var cachedTokens = authContext.TokenCache.ReadItems().Where(a => a.Resource == AzureAdOptions.Settings.CentralRegistryResourceAppId);
                        foreach (TokenCacheItem tci in cachedTokens)
                        {
                            authContext.TokenCache.DeleteItem(tci);
                        }

                        ViewBag.ErrorMessage = "UnexpectedError";
                        ModelSchema newModelSchema = new ModelSchema();
                        newModelSchema.Name = "(No data schemas exist in the system)";
                        schemaList.Add(newModelSchema);
                        return(View(schemaList));
                    }
                }
            }
            catch (Exception ex)
            {
                if (HttpContext.Request.Query["reauth"] == "True")
                {
                    //
                    // Send an OpenID Connect sign-in request to get a new set of tokens.
                    // If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
                    // The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
                    //
                    return(new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme));
                }
                //
                // The user needs to re-authorize.  Show them a message to that effect.
                //

                ModelSchema newModelSchema = new ModelSchema();
                newModelSchema.Name = "(Sign-in required to view data schemas.)";
                schemaList.Add(newModelSchema);
                ViewBag.ErrorMessage = "AuthorizationRequired" + ex.Message;
                return(View(schemaList));
            }
            //
            // If the call failed for any other reason, show the user an error.
            //
            return(View("Error"));
        }
        public async Task <ActionResult> Index(string name, string description, string schemajson)
        {
            if (ModelState.IsValid)
            {
                //
                // Retrieve the user's tenantID and access token
                //
                AuthenticationResult result     = null;
                List <ModelSchema>   schemaList = new List <ModelSchema>();

                try
                {
                    string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
                    AuthenticationContext authContext = new AuthenticationContext(AzureAdOptions.Settings.CentralRegistryAuthority, new NaiveSessionCache(userObjectID, HttpContext.Session));
                    ClientCredential      credential  = new ClientCredential(AzureAdOptions.Settings.ClientId, AzureAdOptions.Settings.ClientSecret);
                    result = await authContext.AcquireTokenAsync(AzureAdOptions.Settings.CentralRegistryResourceAppId, credential);

                    if (string.IsNullOrEmpty(description))
                    {
                        description = name;
                    }

                    // Forms encode schema record, to POST to the MRSDistComp Web API.
                    HttpContent content = new StringContent(JsonConvert.SerializeObject(new { schemaname = name, schemadesc = description, schema = schemajson, broadcast = true }),
                                                            System.Text.Encoding.UTF8,
                                                            "application/json");

                    //
                    // Add new data schema to the data catalog.
                    //
                    HttpClient         client  = new HttpClient();
                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, AzureAdOptions.Settings.CentralRegistryBaseAddress + "/api/RegisterSchema");
                    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
                    request.Content = content;
                    HttpResponseMessage response = await client.SendAsync(request);

                    //
                    // Return the view.
                    //
                    if (response.IsSuccessStatusCode)
                    {
                        return(RedirectToAction("Index"));
                    }
                    else
                    {
                        //
                        // If the call failed with access denied, then drop the current access token from the cache,
                        //     and show the user an error indicating they might need to sign-in again.
                        //
                        if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                        {
                            var cachedTokens = authContext.TokenCache.ReadItems().Where(a => a.Resource == AzureAdOptions.Settings.CentralRegistryResourceAppId);
                            foreach (TokenCacheItem tci in cachedTokens)
                            {
                                authContext.TokenCache.DeleteItem(tci);
                            }

                            ViewBag.ErrorMessage = "UnexpectedError";
                            ModelSchema newModelSchema = new ModelSchema();
                            newModelSchema.Name = "(Sign-in required to view data catalog.)";
                            schemaList.Add(newModelSchema);
                            return(View(newModelSchema));
                        }
                    }
                }
                catch
                {
                    //
                    // The user needs to re-authorize.  Show them a message to that effect.
                    //
                    ModelSchema newModelSchema = new ModelSchema();
                    newModelSchema.Name = "(No schemas exist in the data catalog)";
                    schemaList.Add(newModelSchema);
                    ViewBag.ErrorMessage = "AuthorizationRequired";
                    return(View(schemaList));
                }
                //
                // If the call failed for any other reason, show the user an error.
                //
                return(View("Error"));
            }
            return(View("Error"));
        }
        public ModelSchema ConvertSchema(IEdmModel edmModel)
        {
            var entityContainers       = edmModel.EntityContainers().ToArray();
            var defaultEntityContainer = entityContainers.First(_ => edmModel.IsDefaultEntityContainer(_));
            var entitySets             = defaultEntityContainer.EntitySets().ToArray();

            var modelSchema     = new ModelSchema();
            var modelEntityRoot = new ModelEntity();
            var complexTypeRoot = new ModelComplexType();

            // TODO: add ns
            modelEntityRoot.Name = new ModelEntityName(defaultEntityContainer.Namespace, null, defaultEntityContainer.Name);
            complexTypeRoot.Name = new ModelEntityName(defaultEntityContainer.Namespace, null, defaultEntityContainer.Name);

            modelEntityRoot.EntityType = complexTypeRoot;
            modelSchema.Entities.Add(modelEntityRoot);
            modelEntityRoot.Kind = ModelEntityKind.Container;

            foreach (var entitySet in entitySets)
            {
                var elementType = entitySet.ElementType;
                var complexType = new ModelComplexType();
                var modelEntity = new ModelEntity();
                complexType.Name       = new ModelEntityName(elementType.Namespace, null, elementType.Name);
                modelEntity.Name       = new ModelEntityName(null, null, entitySet.Name);
                modelEntity.EntityType = complexType;
                modelEntity.Kind       = ModelEntityKind.EntitySet;

                modelSchema.ComplexTypes.Add(complexType);
                modelSchema.Entities.Add(modelEntity);


                var declaredStructuralProperties = elementType.DeclaredStructuralProperties().ToArray();
                foreach (var declaredStructuralProperty in declaredStructuralProperties)
                {
                    var declaredStructuralPropertyType           = declaredStructuralProperty.Type;
                    var declaredStructuralPropertyTypeDefinition = declaredStructuralPropertyType.Definition;
                    var modelProperty = new ModelProperty();
                    modelProperty.Name = declaredStructuralProperty.Name;
                    if (declaredStructuralPropertyType.IsPrimitive())
                    {
                        var modelPropertyType = new ModelScalarType();
                        var vas = declaredStructuralProperty.VocabularyAnnotations(edmModel).ToArray();
                        if (declaredStructuralPropertyTypeDefinition is IEdmSchemaElement edmSchemaElement)
                        {
                            modelPropertyType.Name = new ModelEntityName(edmSchemaElement.Namespace, null, edmSchemaElement.Name);
                        }
                        else
                        {
                            modelPropertyType.Name = new ModelEntityName(null, null, declaredStructuralPropertyType.FullName());
                        }
                        modelPropertyType.IsNullable = declaredStructuralPropertyType.IsNullable;
                        modelProperty.Type           = modelPropertyType;
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                    complexType.Properties.Add(modelProperty);
                }

                //complexType.Properties
            }

            foreach (var entitySet in entitySets)
            {
                var entityName  = new ModelEntityName(null, null, entitySet.Name);
                var modelEntity = modelSchema.Entities.FirstOrDefault(_ => _.Name == entityName);

                var navigationTargets = entitySet.NavigationTargets.ToArray();
                foreach (var navigationTarget in navigationTargets)
                {
                    //
                    var navigationProperty = navigationTarget.NavigationProperty;

                    if (navigationProperty is IEdmNavigationProperty edmNavigationProperty)
                    {
                        if (navigationProperty.ContainsTarget)
                        {
                        }
                    }
                    var navigationPropertyPartner = navigationProperty.Partner;
                    var targetEntitySet           = navigationTarget.TargetEntitySet;
                    //
                    var naviFromProperties = navigationProperty.DependentProperties?.ToArray();
                    var naviToProperties   = navigationPropertyPartner.DependentProperties?.ToArray();

                    var modelRelation     = new ModelRelation();
                    var targetEntityName  = new ModelEntityName(null, null, targetEntitySet.Name);
                    var targetModelEntity = modelSchema.Entities.FirstOrDefault(_ => _.Name == targetEntityName);
                    modelRelation.Name = navigationTarget.TargetEntitySet.Name;

                    //modelRelation.MasterEntity =
                    //modelRelation.ForeignEntity = targetModelEntity;
                    modelRelation.ForeignName = targetEntityName;
                    modelSchema.Relations.Add(modelRelation);
                }
            }

            return(modelSchema);
        }
Example #8
0
        public ModelComplexType BuildComplexTypeNavigationProperty(EdmxModel edmxModel, ModelSchema modelSchema, CsdlEntityTypeModel entityTypeModel, MetaModelBuilder metaModelBuilder, ModelErrors errors)
        {
            ModelComplexType result     = null;
            var entityTypeModelName     = entityTypeModel.Name;
            var entityTypeModelFullName = entityTypeModel.FullName;

            var lstFound = modelSchema.ComplexTypes.FindByKey2(entityTypeModelFullName ?? entityTypeModelName);

            if (lstFound.Count == 1)
            {
                result = lstFound[0];
            }
            else if (lstFound.Count > 1)
            {
                errors.AddErrorOrThrow(new ModelErrorInfo($"found key {entityTypeModelFullName ?? entityTypeModelName} #{lstFound.Count} times.", entityTypeModelFullName ?? entityTypeModelName));
                result = lstFound[0];
            }
            else
            {
                result = BuildComplexType(edmxModel, modelSchema, entityTypeModel, metaModelBuilder, errors);
            }
            if (result == null)
            {
                return(null);
            }

            foreach (var navigationProperty in entityTypeModel.NavigationProperty)
            {
                if (navigationProperty.RelationshipName is null)
                {
                    //navigationProperty.Name
                    //navigationProperty.TypeModel
                    //navigationProperty.PartnerModel
                    throw new NotImplementedException("v4 NavigationProperty");
                }
                else
                {
                    // v3
                    //if (navigationProperty.FromRoleModel is null) {
                    //} else {
                    //}

                    if (navigationProperty.ToRoleModel is null)
                    {
                    }
                    else
                    {
                        var toModel           = navigationProperty.ToRoleModel.TypeModel;
                        var lstToComplexTypes = modelSchema.ComplexTypes.FindByKey2(toModel.FullName);
                        if (lstToComplexTypes.Count == 1)
                        {
                            var toComplexType = lstToComplexTypes[0];
                            var navigationPropertyExternalName = navigationProperty.Name;
#warning magic needed here
                            var navigationPropertyName = navigationPropertyExternalName;

                            bool isCollection = false;
                            bool isOptional   = false;
                            switch (navigationProperty.ToRoleModel.GetMultiplicity())
                            {
                            case MultiplicityKind.Unknown:
                                break;

                            case MultiplicityKind.OneOptional:
                                isOptional = true;
                                break;

                            case MultiplicityKind.One:
                                break;

                            case MultiplicityKind.Multiple:
                                isCollection = true;
                                break;

                            default:
                                break;
                            }

                            var modelNavigationProperty = result.CreateNavigationProperty(
                                navigationPropertyName,
                                navigationPropertyExternalName,
                                toComplexType,
                                isOptional,
                                isCollection
                                );
                        }
                    }
                }
            }

            /*
             */
            return(result);
        }
Example #9
0
        public ModelComplexType BuildComplexType(EdmxModel edmxModel, ModelSchema modelSchema, CsdlEntityTypeModel entityTypeModel, MetaModelBuilder metaModelBuilder, ModelErrors errors)
        {
            var entityTypeModelName     = entityTypeModel.Name;
            var entityTypeModelFullName = entityTypeModel.FullName;

            var lstFound = modelSchema.ComplexTypes.FindByKey2(entityTypeModelFullName ?? entityTypeModelName);

            if (lstFound.Count == 1)
            {
                return(lstFound[0]);
            }
            else if (lstFound.Count > 1)
            {
                errors.AddErrorOrThrow(new ModelErrorInfo($"found key {entityTypeModelFullName ?? entityTypeModelName} #{lstFound.Count} times.", entityTypeModelFullName ?? entityTypeModelName));
                return(lstFound[0]);
            }

            var modelComplexType = metaModelBuilder.CreateModelComplexType(
                entityTypeModelName,
                entityTypeModelFullName,
                errors);

            if (modelComplexType.Owner == null)
            {
                modelSchema.ComplexTypes.Add(modelComplexType);
            }

            foreach (var property in entityTypeModel.Property)
            {
                ModelScalarType modelScalarType = null;
                ModelScalarType suggestedType   = property.SuggestType(metaModelBuilder);

                // TODO: thinkof EdmxModelBuilder Build ScalarType
                //if (property.ScalarType != null) {
                //    property.ScalarType.FullName
                //}

                modelScalarType = metaModelBuilder.CreateModelScalarType(
                    entityTypeModelName,
                    entityTypeModelFullName,
                    property.Name,
                    null,
                    property.TypeName,
                    suggestedType,
                    property.MaxLength,
                    property.FixedLength,
                    property.Nullable,
                    property.Precision,
                    property.Scale,
                    errors
                    );

                var modelProperty = metaModelBuilder.CreateModelProperty(
                    entityTypeModelName,
                    entityTypeModelFullName,
                    property.Name,
                    null,
                    errors
                    );
                if (modelProperty.Type == null)
                {
                    modelProperty.Type = modelScalarType;
                }
                if (modelProperty.Owner == null)
                {
                    modelComplexType.Properties.Add(modelProperty);
                }
            }
            var primaryKey = entityTypeModel.Keys;

            if (primaryKey.Count > 0)
            {
                var modelIndex = metaModelBuilder.CreateModelIndex(
                    entityTypeModelName,
                    entityTypeModelFullName,
                    "PrimaryKey",
                    null,
                    errors
                    );
                modelIndex.IsPrimaryKey = true;
                if (modelIndex.Owner == null)
                {
                    modelComplexType.Indexes.Add(modelIndex);
                }
                foreach (var keyModel in entityTypeModel.Keys)
                {
                    var modelIndexProperty = metaModelBuilder.CreateModelIndexProperty(
                        entityTypeModelName,
                        entityTypeModelFullName,
                        modelIndex.Name,
                        modelIndex.ExternalName,
                        keyModel.Name,
                        null,
                        //keyModel.Property,
                        errors
                        );
                    if (modelIndexProperty.Owner == null)
                    {
                        modelIndex.Properties.Add(modelIndexProperty);
                    }
                }
            }

            return(modelComplexType);
        }
Example #10
0
        public ModelSchema Build(
            EdmxModel edmxModel,
            ModelSchema modelSchema,
            MetaModelBuilder metaModelBuilder,
            ModelErrors errors)
        {
            if (modelSchema == null)
            {
                modelSchema = new ModelSchema();
            }
            //if (metaMappingSchema == null) { metaMappingSchema = new MetaMappingSchema(); }
            if (metaModelBuilder == null)
            {
                metaModelBuilder = new MetaModelBuilder();
            }

            if (!edmxModel.IsFrozen())
            {
                edmxModel.AddCoreSchemaIfNeeded(errors);
                edmxModel.Freeze();
            }

            var defaultEntityContainers = edmxModel.DataServices.SelectMany(_ => _.EntityContainer).Where(_ => _.IsDefaultEntityContainer).ToList();

            if (defaultEntityContainers.Count != 1)
            {
                defaultEntityContainers = edmxModel.DataServices.SelectMany(_ => _.EntityContainer).ToList();
            }
            if (defaultEntityContainers.Count != 1)
            {
                errors.AddErrorOrThrow($"DefaultEntityContainers #{defaultEntityContainers.Count} found.", "model");
                return(modelSchema);
            }
            var defaultEntityContainer = defaultEntityContainers[0];

            edmxModel.ResolveNames(errors);
            if (errors.HasErrors())
            {
                return(modelSchema);
            }

            foreach (var dataServices in edmxModel.DataServices)
            {
                foreach (var scalarTypeModel in dataServices.ScalarTypeModel)
                {
                    this.BuildScalarType(edmxModel, modelSchema, scalarTypeModel, metaModelBuilder, errors);
                }
            }
            foreach (var dataServices in edmxModel.DataServices)
            {
                foreach (var entityTypeModel in dataServices.EntityType)
                {
                    this.BuildComplexType(edmxModel, modelSchema, entityTypeModel, metaModelBuilder, errors);
                }
            }
            foreach (var dataServices in edmxModel.DataServices)
            {
                foreach (var entityTypeModel in dataServices.EntityType)
                {
                    this.BuildComplexTypeNavigationProperty(edmxModel, modelSchema, entityTypeModel, metaModelBuilder, errors);
                }
            }
            foreach (var dataServices in edmxModel.DataServices)
            {
                foreach (var association in dataServices.Association)
                {
                    this.BuildAssociation(edmxModel, modelSchema, association, metaModelBuilder, errors);
                }
            }
            //foreach (var dataServices in edmxModel.DataServices) {
            //    foreach (var entityContainer in dataServices.EntityContainer) {
            //        if (entityContainer.IsDefaultEntityContainer) { continue; }
            //    }
            //}


            foreach (var entitySet in defaultEntityContainer.EntitySet)
            {
                var entityTypeModel = entitySet.EntityTypeModel;
                if (entityTypeModel == null)
                {
                    errors.AddErrorOrThrow("entitySet.EntityTypeModel not found", entitySet.Name);
                }
                else
                {
                    var entityTypeModelName     = entityTypeModel.Name;
                    var entityTypeModelFullName = entityTypeModel.FullName;

                    var modelComplexType = this.BuildComplexType(edmxModel, modelSchema, entityTypeModel, metaModelBuilder, errors);

                    var entitySetName = entitySet.Name;
                    var modelEntity   = metaModelBuilder.CreateModelEntity(
                        entitySetName,
                        ModelEntityKind.EntitySet,
                        errors);
                    if (modelEntity.Owner == null)
                    {
                        modelSchema.Entities.Add(modelEntity);
                    }
                    if (modelComplexType is null)
                    {
                        errors.AddErrorOrThrow($"{entityTypeModelFullName ?? entityTypeModelName} not found", entitySet.Name);
                    }
                    else
                    {
                        modelEntity.EntityType = modelComplexType;
                    }
                }
            }

            //foreach (var associationSet in defaultEntityContainer.AssociationSet) {
            //    foreach (var end in associationSet.End) {
            //        if (!(end.EntitySetModel is null)) {
            //            var roleName = d.RoleName;
            //        }
            //    }
            //}

            return(modelSchema);
        }
        public void BuildModelSqlDatabase(
            ModelSchema modelSchema,
            ModelSqlDatabase modelDatabase,
            MetaModelBuilder metaModelBuilder,
            ModelErrors errors)
        {
            foreach (var modelEntitySource in modelSchema.Entities)
            {
                var modelEntityTypeSource = modelEntitySource.EntityType;
                if (modelEntityTypeSource is null)
                {
#warning SOON add error
                }
                else
                {
                    var tableNameTarget    = modelEntitySource.ExternalName ?? modelEntitySource.Name;
                    var sqlTableNameTarget = SqlName.Parse(tableNameTarget, ObjectLevel.Object);
                    var tableTarget        = ModelSqlTable.Ensure(modelDatabase, sqlTableNameTarget);

                    foreach (var property in modelEntityTypeSource.Properties)
                    {
                        var            sqlColumnNameTarget = SqlName.Parse(property.ExternalName ?? property.Name, ObjectLevel.Object);
                        ModelSqlColumn column = ModelSqlColumn.Ensure(tableTarget, sqlColumnNameTarget.Name);
                        if (property.Type is ModelScalarType propertyScalarType)
                        {
                            var clrTypeSource = property.GetClrType();
                            var typeName      = propertyScalarType.Name;
#warning TODO SOON better Scalar Type Handling this is ugly
                            if (!(clrTypeSource is null))
                            {
                                var innerNullableClrTypeSource = ((clrTypeSource.IsValueType) ? Nullable.GetUnderlyingType(clrTypeSource) : null) ?? clrTypeSource;
                                if (!(column.SqlType is null))
                                {
                                    var clrScalarTypeTarget = column.SqlType.GetScalarType()?.GetClrType();
                                    var innerNullableClrScalarTypeTarget = ((clrScalarTypeTarget.IsValueType) ? Nullable.GetUnderlyingType(clrScalarTypeTarget) : null) ?? clrScalarTypeTarget;
                                    if (!(clrScalarTypeTarget is null) && (clrScalarTypeTarget.IsAssignableFrom(innerNullableClrScalarTypeTarget)))
                                    {
                                        // ok
                                    }
                                    else
                                    {
                                        column.SqlType = null;
                                    }
                                }
                            }
                            if (column.SqlType is null)
                            {
                                var sqlTypeTarget = modelDatabase.Types.GetValueOrDefault(SqlName.Parse(typeName, ObjectLevel.Object));
                                if (!(sqlTypeTarget is null))
                                {
                                    column.SqlType = sqlTypeTarget;
                                }
                                else
                                {
                                    if (!(clrTypeSource is null))
                                    {
                                        var innerNullableClrTypeSource = ((clrTypeSource.IsValueType) ? Nullable.GetUnderlyingType(clrTypeSource) : null) ?? clrTypeSource;
                                        var lstTypes = new List <ModelSqlType>();
                                        foreach (var type in modelDatabase.Types)
                                        {
                                            var clrScalarTypeTarget = type.GetScalarType()?.GetClrType();
                                            if (clrScalarTypeTarget is null)
                                            {
                                                continue;
                                            }
                                            var innerNullableClrScalarTypeTarget = ((clrScalarTypeTarget.IsValueType) ? Nullable.GetUnderlyingType(clrScalarTypeTarget) : null) ?? clrScalarTypeTarget;
                                            if (innerNullableClrTypeSource.Equals(innerNullableClrScalarTypeTarget))
                                            {
                                                lstTypes.Add(type);
                                            }
                                            else if (innerNullableClrTypeSource.IsAssignableFrom(innerNullableClrScalarTypeTarget))
                                            {
                                                lstTypes.Add(type);
                                            }
                                        }
                                        if (lstTypes.Count == 1)
                                        {
                                            sqlTypeTarget  = lstTypes[0];
                                            column.SqlType = sqlTypeTarget;
                                        }
                                        else if (lstTypes.Count > 1)
                                        {
                                            sqlTypeTarget = null;
                                            if (clrTypeSource == typeof(string))
                                            {
                                                sqlTypeTarget = modelDatabase.Types.GetValueOrDefault(SqlName.Parse("[sys].[nvarchar]", ObjectLevel.Object));
                                            }
                                            else if (clrTypeSource == typeof(DateTime))
                                            {
                                                sqlTypeTarget = modelDatabase.Types.GetValueOrDefault(SqlName.Parse("[sys].[datetime2]", ObjectLevel.Object));
                                            }
                                            else if (clrTypeSource == typeof(DateTime?))
                                            {
                                                sqlTypeTarget = modelDatabase.Types.GetValueOrDefault(SqlName.Parse("[sys].[datetime2]", ObjectLevel.Object));
                                            }
                                            if (sqlTypeTarget is null)
                                            {
                                                sqlTypeTarget = lstTypes[0];
                                            }
                                            column.SqlType = sqlTypeTarget;
                                        }
                                        else
                                        {
                                            errors.Add(new ModelErrorInfo($"Unknown mapping for {typeName} - {clrTypeSource}.", column.NameSql));
                                            sqlTypeTarget  = modelDatabase.Types.GetValueOrDefault(SqlName.Parse("[sys].[nvarchar]", ObjectLevel.Object));
                                            column.SqlType = sqlTypeTarget;
                                        }
                                    }
                                }
                                sqlTypeTarget = column.SqlType;
                                if (sqlTypeTarget is null)
                                {
                                    errors.Add(new ModelErrorInfo($"column.SqlType is null.", column.NameSql));
                                }
                                else
                                {
                                    sqlTypeTarget.Nullable = propertyScalarType.Nullable.GetValueOrDefault(true);
                                    if (propertyScalarType.MaxLength.HasValue)
                                    {
                                        sqlTypeTarget.MaxLength = propertyScalarType.MaxLength;
                                    }
                                    else
                                    {
                                        //if (typeof(string).Equals(sqlTypeTarget.GetScalarType().GetClrType())) {
                                        //    sqlTypeTarget.MaxLength = -1;
                                        //}
                                    }
                                }
                            } // if (column.SqlType is null)
                        }
        public void BuildModelSchema(
            ModelSqlDatabase modelDatabase,
            ModelSchema modelSchema,
            MetaModelBuilder metaModelBuilder,
            ModelErrors errors)
        {
            if (modelSchema == null)
            {
                modelSchema = new ModelSchema();
            }
            if (metaModelBuilder == null)
            {
                metaModelBuilder = new MetaModelBuilder();
            }

            // modelDatabase.Freeze();

            foreach (var table in modelDatabase.Tables)
            {
                var entityTypeModelName     = table.Name.GetQFullName(null, 2);
                var entityTypeModelFullName = table.Name.GetQFullName("[", 2);

                var modelComplexType = metaModelBuilder.CreateModelComplexType(
                    entityTypeModelName,
                    entityTypeModelFullName,
                    errors);

                if (modelComplexType.Owner == null)
                {
                    modelSchema.ComplexTypes.Add(modelComplexType);
                }

                foreach (var column in table.Columns)
                {
                    ModelScalarType modelScalarType = null;
                    ModelScalarType suggestedType   = column.SuggestType(metaModelBuilder);

                    modelScalarType = metaModelBuilder.CreateModelScalarType(
                        entityTypeModelName,
                        entityTypeModelFullName,
                        column.Name.GetQName(),
                        null,
                        column.SqlType.Name.GetQFullName(),
                        suggestedType,
                        column.MaxLength,
                        column.FixedLength,
                        column.Nullable,
                        column.Precision,
                        column.Scale,
                        errors
                        );
                    var columnName         = column.Name.GetQFullName(null, 1);
                    var columnExternalName = column.Name.GetQFullName("[", 1);

                    var modelProperty = metaModelBuilder.CreateModelProperty(
                        entityTypeModelName,
                        entityTypeModelFullName,
                        columnName,
                        columnExternalName,
                        errors
                        );
                    if (modelProperty.Type == null)
                    {
                        modelProperty.Type = modelScalarType;
                    }
                    if (modelProperty.Owner == null)
                    {
                        modelComplexType.Properties.Add(modelProperty);
                    }
                }

                var tableIndexes    = table.Indexes.ToList();
                var lstPrimaryIndex = tableIndexes.Where(sqlIndex => sqlIndex.IsPrimaryKey).ToList();
                var primaryIndex    = lstPrimaryIndex.FirstOrDefault();
                if (lstPrimaryIndex.Count == 1)
                {
                    //var sqlIndex = lstPrimaryIndex[0];
                    // OK
                }
                else if (lstPrimaryIndex.Count > 1)
                {
                    errors.AddErrorOrThrow($"More than one ({lstPrimaryIndex.Count}) primary key.", table.NameSql);
                }
                else
                {
#warning think of no primary key
                }

                foreach (var sqlIndex in tableIndexes)
                {
#warning have indexes a schema??
                    var modelIndex = metaModelBuilder.CreateModelIndex(entityTypeModelName, entityTypeModelFullName, sqlIndex.Name.Name, sqlIndex.Name.Name, errors);
                    //modelIndex.IsPrimaryKey = sqlIndex.IsPrimaryKey;
                    modelIndex.IsPrimaryKey = ReferenceEquals(sqlIndex, primaryIndex);
                    modelComplexType.Indexes.Add(modelIndex);
                    foreach (var column in sqlIndex.Columns)
                    {
                        var modelIndexProperty = metaModelBuilder.CreateModelIndexProperty(
                            entityTypeModelName,
                            entityTypeModelFullName,
                            sqlIndex.Name.Name,
                            sqlIndex.Name.Name,
                            column.Name.Name,
                            null,
                            errors
                            );
                        modelIndex.Properties.Add(modelIndexProperty);
                    }
                }
                var entitySetName = table.Name.GetQFullName(null, 2);
                var modelEntity   = metaModelBuilder.CreateModelEntity(
                    entitySetName,
                    ModelEntityKind.EntitySet,
                    errors);
                if (modelEntity.Owner == null)
                {
                    modelSchema.Entities.Add(modelEntity);
                }
                modelEntity.EntityType = modelComplexType;
            }
        }