public static EntityConfigurationClassDefinition GetEntityConfigurationClassDefinition(this EntityFrameworkCoreProject project, ITable table, bool isDomainDrivenDesign)
        {
            var definition = new EntityConfigurationClassDefinition
            {
                Namespaces =
                {
                    "Microsoft.EntityFrameworkCore",
                    "Microsoft.EntityFrameworkCore.Metadata.Builders"
                },
                AccessModifier = AccessModifier.Internal,
                Name           = project.GetEntityConfigurationName(table),
                DbObject       = table
            };

            if (isDomainDrivenDesign)
            {
                definition.Namespace = project.GetDomainConfigurationsNamespace(project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema);
                definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema));
            }
            else
            {
                definition.Namespace = project.Database.HasDefaultSchema(table) ? project.GetDataLayerConfigurationsNamespace() : project.GetDataLayerConfigurationsNamespace(table.Schema);
                definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema));
            }

            // todo: Check logic to build property's name

            var propertyType = "";

            if (table.HasSameEnclosingName())
            {
                propertyType = string.Join(".", (new string[] { project.ProjectNamespaces.EntityLayer, project.Database.HasDefaultSchema(table) ? string.Empty : table.Schema, project.GetEntityName(table) }).Where(item => !string.IsNullOrEmpty(item)));
            }
            else
            {
                propertyType = project.GetEntityName(table);
            }

            definition.Implements.Add(string.Format("IEntityTypeConfiguration<{0}>", propertyType));

            var configLines = new List <ILine>
            {
                new CommentLine(" Set configuration for entity")
            };

            if (string.IsNullOrEmpty(table.Schema))
            {
                configLines.Add(new CodeLine("builder.ToTable(\"{0}\");", table.Name));
            }
            else
            {
                configLines.Add(new CodeLine("builder.ToTable(\"{0}\", \"{1}\");", table.Name, table.Schema));
            }

            configLines.Add(new EmptyLine());

            var columns = default(List <Column>);

            if (table.PrimaryKey == null || table.PrimaryKey.Key.Count == 0)
            {
                configLines.Add(LineHelper.Warning("Add configuration for entity's key"));
                configLines.Add(new EmptyLine());
            }
            else
            {
                configLines.Add(new CommentLine(" Set key for entity"));

                if (project.Version >= EntityFrameworkCoreVersion.Version_3_0)
                {
                    configLines.Add(new CodeLine("builder.HasNoKey();"));
                }
                else
                {
                    if (table.PrimaryKey.Key.Count == 1)
                    {
                        configLines.Add(new CodeLine("builder.HasKey(p => p.{0});", project.CodeNamingConvention.GetPropertyName(table.PrimaryKey.Key[0])));
                        configLines.Add(new EmptyLine());
                    }
                    else if (table.PrimaryKey.Key.Count > 1)
                    {
                        configLines.Add(new CodeLine("builder.HasKey(p => new {{ {0} }});", string.Join(", ", table.PrimaryKey.Key.Select(item => string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(item))))));
                        configLines.Add(new EmptyLine());
                    }
                }
            }

            if (table.Identity != null)
            {
                configLines.Add(new CommentLine(" Set identity for entity (auto increment)"));

                if (project.Version >= EntityFrameworkCoreVersion.Version_3_0)
                {
                    configLines.Add(new CodeLine("builder.Property(p => p.{0}).UseIdentityColumn();", project.CodeNamingConvention.GetPropertyName(table.Identity.Name)));
                }
                else
                {
                    configLines.Add(new CodeLine("builder.Property(p => p.{0}).UseSqlServerIdentityColumn();", project.CodeNamingConvention.GetPropertyName(table.Identity.Name)));
                }

                configLines.Add(new EmptyLine());
            }

            columns = table.Columns;

            configLines.Add(new CommentLine(" Set configuration for columns"));

            for (var i = 0; i < columns.Count; i++)
            {
                var column = columns[i];

                var valueConversion = default(Type);

                if (project.Database.HasTypeMappedToClr(column))
                {
                    var lines = new List <string>
                    {
                        string.Format("Property(p => p.{0})", project.GetPropertyName(table, column))
                    };

                    if (string.Compare(column.Name, project.GetPropertyName(table, column)) != 0)
                    {
                        lines.Add(string.Format("HasColumnName(\"{0}\")", column.Name));
                    }

                    if (project.Database.ColumnIsByteArray(column))
                    {
                        lines.Add(string.Format("HasColumnType(\"{0}({1})\")", column.Type, column.Length));
                    }
                    else if (project.Database.ColumnIsDecimal(column))
                    {
                        lines.Add(string.Format("HasColumnType(\"{0}({1}, {2})\")", column.Type, column.Prec, column.Scale));
                    }
                    else if (project.Database.ColumnIsDouble(column) || project.Database.ColumnIsSingle(column))
                    {
                        lines.Add(string.Format("HasColumnType(\"{0}({1})\")", column.Type, column.Prec));
                    }
                    else if (project.Database.ColumnIsString(column))
                    {
                        if (column.Length <= 0)
                        {
                            lines.Add(string.Format("HasColumnType(\"{0}(max)\")", column.Type));
                        }
                        else
                        {
                            lines.Add(string.Format("HasColumnType(\"{0}\")", column.Type));
                            lines.Add(string.Format("HasMaxLength({0})", column.Length));
                        }
                    }
                    else
                    {
                        lines.Add(string.Format("HasColumnType(\"{0}\")", column.Type));
                    }

                    // Use ValueConversionMaps to detect and apply ValueConversion Type based on Type

                    if (project.ValueConversionMaps.TryGetValue(column.Type, out valueConversion) == true)
                    {
                        lines.Add($".HasConversion(typeof({valueConversion?.FullName}))");
                    }

                    if (!column.Nullable)
                    {
                        lines.Add("IsRequired()");
                    }

                    configLines.Add(new CodeLine("builder"));

                    foreach (var line in lines)
                    {
                        configLines.Add(new CodeLine(1, ".{0}", line));
                    }

                    configLines.Add(new CodeLine(1, ";"));
                    configLines.Add(new EmptyLine());
                }
                else
                {
                    configLines.Add(new CodeLine("builder.Ignore(p => p.{0});", project.GetPropertyName(table, column)));
                    configLines.Add(new EmptyLine());
                }
            }

            var projectSelection = project.GetSelection(table);

            for (var i = 0; i < columns.Count; i++)
            {
                var column = columns[i];

                if (!string.IsNullOrEmpty(projectSelection.Settings.ConcurrencyToken) && string.Compare(column.Name, projectSelection.Settings.ConcurrencyToken) == 0)
                {
                    configLines.Add(new CommentLine(" Set concurrency token for entity"));
                    configLines.Add(new CodeLine("builder"));
                    configLines.Add(new CodeLine(1, ".Property(p => p.{0})", project.GetPropertyName(table, column)));
                    configLines.Add(new CodeLine(1, ".ValueGeneratedOnAddOrUpdate()"));
                    configLines.Add(new CodeLine(1, ".IsConcurrencyToken();"));
                    configLines.Add(new EmptyLine());
                }
            }

            if (projectSelection.Settings.AddConfigurationForUniquesInFluentAPI && table.Uniques.Count > 0)
            {
                configLines.Add(new CommentLine(" Add configuration for uniques"));
                configLines.Add(new EmptyLine());

                foreach (var unique in table.Uniques)
                {
                    configLines.Add(new CodeLine("builder"));

                    if (unique.Key.Count == 1)
                    {
                        configLines.Add(new CodeLine(1, ".HasIndex(p => p.{0})", project.CodeNamingConvention.GetPropertyName(unique.Key.First())));
                        configLines.Add(new CodeLine(1, ".IsUnique()"));
                    }
                    else
                    {
                        configLines.Add(new CodeLine(1, ".HasIndex(p => new {{ {0} }})", string.Join(", ", unique.Key.Select(item => string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(item))))));
                        configLines.Add(new CodeLine(1, ".IsUnique()"));
                    }

                    configLines.Add(new CodeLine(1, ".HasName(\"{0}\");", unique.ConstraintName));
                    configLines.Add(new EmptyLine());
                }
            }

            if (projectSelection.Settings.AddConfigurationForForeignKeysInFluentAPI && projectSelection.Settings.DeclareNavigationProperties && table.ForeignKeys.Count > 0)
            {
                configLines.Add(new CommentLine(" Add configuration for foreign keys"));
                configLines.Add(new EmptyLine());

                foreach (var foreignKey in table.ForeignKeys)
                {
                    var foreignTable = project.Database.FindTable(foreignKey.References);

                    if (foreignTable == null || foreignKey.Key.Count == 0)
                    {
                        continue;
                    }

                    if (foreignKey.Key.Count == 1)
                    {
                        var foreignProperty = foreignKey.GetParentNavigationProperty(foreignTable, project);

                        configLines.Add(new CodeLine("builder"));
                        configLines.Add(new CodeLine(1, ".HasOne(p => p.{0})", foreignProperty.Name));
                        configLines.Add(new CodeLine(1, ".WithMany(b => b.{0})", project.GetNavigationPropertyName(table)));
                        configLines.Add(new CodeLine(1, ".HasForeignKey(p => {0})", string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(foreignKey.Key.First()))));
                        configLines.Add(new CodeLine(1, ".HasConstraintName(\"{0}\");", foreignKey.ConstraintName));
                        configLines.Add(new EmptyLine());
                    }
                    else
                    {
                        configLines.Add(LineHelper.Warning(" Add logic for foreign key with multiple key"));
                    }
                }
            }

            if (projectSelection.Settings.AddConfigurationForDefaultsInFluentAPI && table.Defaults.Count > 0)
            {
                configLines.Add(new CommentLine(" Add configuration for defaults"));
                configLines.Add(new EmptyLine());

                foreach (var def in table.Defaults)
                {
                    var propertyName = def.Key.First();

                    configLines.Add(new CodeLine("builder"));
                    configLines.Add(new CodeLine(1, ".Property(p => p.{0})", project.GetPropertyName(propertyName)));
                    configLines.Add(new CodeLine(1, ".HasDefaultValueSql(\"{0}\");", def.Value));
                    configLines.Add(new EmptyLine());
                }
            }

            definition.Methods.Add(new MethodDefinition
            {
                AccessModifier = AccessModifier.Public,
                Type           = "void",
                Name           = "Configure",
                Parameters     =
                {
                    new ParameterDefinition(string.Format("EntityTypeBuilder<{0}>", propertyType), "builder")
                },
                Lines = configLines
            });

            return(definition);
        }
        public static EntityConfigurationClassDefinition GetEntityConfigurationClassDefinition(this EntityFrameworkCoreProject project, IView view, bool isDomainDrivenDesign)
        {
            var definition = new EntityConfigurationClassDefinition
            {
                Namespaces =
                {
                    "Microsoft.EntityFrameworkCore",
                    "Microsoft.EntityFrameworkCore.Metadata.Builders"
                },
                AccessModifier = AccessModifier.Internal,
                Name           = project.GetEntityConfigurationName(view),
                Implements     =
                {
                    string.Format("IEntityTypeConfiguration<{0}>", project.GetEntityName(view))
                },
                DbObject = view
            };

            if (isDomainDrivenDesign)
            {
                definition.Namespace = project.GetDomainConfigurationsNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema);

                definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema));
                definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema));
            }
            else
            {
                definition.Namespace = project.Database.HasDefaultSchema(view) ? project.GetDataLayerConfigurationsNamespace() : project.GetDataLayerConfigurationsNamespace(view.Schema);

                definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema));
                definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(project.Database.HasDefaultSchema(view) ? string.Empty : view.Schema));
            }

            var configLines = new List <ILine>
            {
                new CommentLine(" Set configuration for entity")
            };

            if (string.IsNullOrEmpty(view.Schema))
            {
                configLines.Add(new CodeLine("builder.ToTable(\"{0}\");", view.Name));
            }
            else
            {
                configLines.Add(new CodeLine("builder.ToTable(\"{0}\", \"{1}\");", view.Name, view.Schema));
            }

            configLines.Add(new EmptyLine());

            var primaryKeys = project
                              .Database
                              .Tables
                              .Where(item => item.PrimaryKey != null)
                              .Select(item => item.GetColumnsFromConstraint(item.PrimaryKey).Select(c => c.Name).First())
                              .ToList();

            var result = view.Columns.Where(item => primaryKeys.Contains(item.Name)).ToList();

            if (result.Count == 0)
            {
                result = view.Columns.Where(item => !item.Nullable).ToList();
            }

            configLines.Add(new CommentLine(" Add configuration for entity's key"));

            if (project.Version >= EntityFrameworkCoreVersion.Version_3_0)
            {
                configLines.Add(new CodeLine("builder.HasNoKey();"));
            }
            else
            {
                if (result.Count == 1)
                {
                    configLines.Add(new CodeLine("builder.HasKey(p => {0});", string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(result.First().Name))));
                }
                else
                {
                    configLines.Add(new CodeLine("builder.HasKey(p => new {{ {0} }});", string.Join(", ", result.Select(item => string.Format("p.{0}", project.CodeNamingConvention.GetPropertyName(item.Name))))));
                }
            }

            configLines.Add(new EmptyLine());

            configLines.Add(new CommentLine(" Set configuration for columns"));

            for (var i = 0; i < view.Columns.Count; i++)
            {
                var column = view.Columns[i];

                var valueConversion = default(Type);

                if (project.Database.HasTypeMappedToClr(column))
                {
                    var lines = new List <string>
                    {
                        string.Format("Property(p => p.{0})", project.GetPropertyName(view, column))
                    };

                    if (string.Compare(column.Name, project.GetPropertyName(view, column)) != 0)
                    {
                        lines.Add(string.Format("HasColumnName(\"{0}\")", column.Name));
                    }

                    else if (project.Database.ColumnIsDecimal(column))
                    {
                        lines.Add(string.Format("HasColumnType(\"{0}({1}, {2})\")", column.Type, column.Prec, column.Scale));
                    }
                    else if (project.Database.ColumnIsDouble(column) || project.Database.ColumnIsSingle(column))
                    {
                        lines.Add(string.Format("HasColumnType(\"{0}({1})\")", column.Type, column.Prec));
                    }
                    if (project.Database.ColumnIsString(column))
                    {
                        lines.Add(column.Length <= 0 ? string.Format("HasColumnType(\"{0}(max)\")", column.Type) : string.Format("HasColumnType(\"{0}({1})\")", column.Type, column.Length));
                    }
                    else
                    {
                        lines.Add(string.Format("HasColumnType(\"{0}\")", column.Type));
                    }

                    // Use ValueConversionMaps to detect and apply ValueConversion Type based on Type

                    if (project.ValueConversionMaps?.TryGetValue(column.Type, out valueConversion) == true)
                    {
                        lines.Add($"HasConversion(typeof({valueConversion?.FullName}))");
                    }

                    configLines.Add(new CodeLine("builder"));

                    foreach (var line in lines)
                    {
                        configLines.Add(new CodeLine(1, ".{0}", line));
                    }

                    configLines.Add(new CodeLine(1, ";"));
                    configLines.Add(new EmptyLine());
                }
                else
                {
                    var lines = new List <string>
                    {
                        string.Format("builder.Ignore(p => p.{0})", project.GetPropertyName(view, column))
                    };

                    configLines.Add(new CodeLine("{0};", string.Join(".", lines)));
                }
            }

            definition.Methods.Add(new MethodDefinition
            {
                AccessModifier = AccessModifier.Public,
                Type           = "void",
                Name           = "Configure",
                Parameters     =
                {
                    new ParameterDefinition(string.Format("EntityTypeBuilder<{0}>", project.GetEntityName(view)), "builder")
                },
                Lines = configLines
            });

            return(definition);
        }
Пример #3
0
        public static DbContextClassDefinition GetDbContextClassDefinition(this EntityFrameworkCoreProject project, ProjectSelection <EntityFrameworkCoreProjectSettings> projectSelection, bool isDomainDrivenDesign)
        {
            var definition = new DbContextClassDefinition
            {
                Namespaces =
                {
                    "System",
                    "Microsoft.EntityFrameworkCore",
                    isDomainDrivenDesign ? project.GetDomainModelsNamespace() : project.GetEntityLayerNamespace()
                },
                Namespace = isDomainDrivenDesign ? project.Name : project.GetDataLayerNamespace(),
                AccessModifier = AccessModifier.Public,
                Name           = project.GetDbContextName(project.Database),
                BaseClass      = "DbContext"
            };

            if (isDomainDrivenDesign)
            {
                if (!projectSelection.Settings.UseDataAnnotations)
                {
                    definition.Namespaces.Add(project.GetDomainConfigurationsNamespace());
                }
            }
            else
            {
                if (!projectSelection.Settings.UseDataAnnotations)
                {
                    definition.Namespaces.Add(project.GetDataLayerConfigurationsNamespace());
                }
            }

            definition.Constructors.Add(new ClassConstructorDefinition
            {
                AccessModifier = AccessModifier.Public,
                Parameters     =
                {
                    new ParameterDefinition(string.Format("DbContextOptions<{0}>", definition.Name), "options")
                },
                Invocation = "base(options)"
            });

            definition.Methods.Add(GetOnModelCreatingMethod(project));

            foreach (var table in project.Database.Tables)
            {
                if (isDomainDrivenDesign)
                {
                    if (!project.Database.HasDefaultSchema(table))
                    {
                        definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(table.Schema));
                    }
                }
                else
                {
                    if (!project.Database.HasDefaultSchema(table))
                    {
                        definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(table.Schema));
                    }
                }

                var existingViews = project.Database.Views.Count(item => item.Name == table.Name);

                var genericTypeName = existingViews == 0 ? project.GetEntityName(table) : project.GetFullEntityName(table);
                var name            = existingViews == 0 ? project.GetDbSetPropertyName(table, projectSelection.Settings.PluralizeDbSetPropertyNames) : project.GetFullDbSetPropertyName(table);

                definition.Properties.Add(
                    new PropertyDefinition
                {
                    AccessModifier = AccessModifier.Public,
                    Type           = string.Format("DbSet<{0}>", genericTypeName),
                    Name           = name,
                    IsAutomatic    = true
                }
                    );
            }

            foreach (var view in project.Database.Views)
            {
                if (isDomainDrivenDesign)
                {
                    if (!project.Database.HasDefaultSchema(view))
                    {
                        definition.Namespaces.AddUnique(project.GetDomainModelsNamespace(view.Schema));
                    }
                }
                else
                {
                    if (!project.Database.HasDefaultSchema(view))
                    {
                        definition.Namespaces.AddUnique(project.GetEntityLayerNamespace(view.Schema));
                    }
                }

                var existingTables = project.Database.Tables.Count(item => item.Name == view.Name);

                var genericTypeName = existingTables == 0 ? project.GetEntityName(view) : project.GetFullEntityName(view);
                var name            = existingTables == 0 ? project.GetDbSetPropertyName(view, projectSelection.Settings.PluralizeDbSetPropertyNames) : project.GetFullDbSetPropertyName(view);

                definition.Properties.Add(
                    new PropertyDefinition
                {
                    AccessModifier = AccessModifier.Public,
                    Type           = string.Format("DbSet<{0}>", genericTypeName),
                    Name           = name,
                    IsAutomatic    = true
                }
                    );
            }

            foreach (var table in project.Database.Tables)
            {
                if (isDomainDrivenDesign)
                {
                    if (!projectSelection.Settings.UseDataAnnotations && !project.Database.HasDefaultSchema(table))
                    {
                        definition.Namespaces.AddUnique(project.GetDomainConfigurationsNamespace(table.Schema));
                    }
                }
                else
                {
                    if (!projectSelection.Settings.UseDataAnnotations && !project.Database.HasDefaultSchema(table))
                    {
                        definition.Namespaces.AddUnique(project.GetDataLayerConfigurationsNamespace(table.Schema));
                    }
                }
            }

            foreach (var view in project.Database.Views)
            {
                if (isDomainDrivenDesign)
                {
                    if (!projectSelection.Settings.UseDataAnnotations && !project.Database.HasDefaultSchema(view))
                    {
                        definition.Namespaces.AddUnique(project.GetDomainConfigurationsNamespace(view.Schema));
                    }
                }
                else
                {
                    if (!projectSelection.Settings.UseDataAnnotations && !project.Database.HasDefaultSchema(view))
                    {
                        definition.Namespaces.AddUnique(project.GetDataLayerConfigurationsNamespace(view.Schema));
                    }
                }
            }

            var scalarFunctions = project.Database.GetScalarFunctions();

            foreach (var scalarFunction in scalarFunctions)
            {
                var parameterType = string.Empty;

                if (project.Database.HasTypeMappedToClr(scalarFunction.Parameters[0]))
                {
                    var clrType = project.Database.GetClrMapForType(scalarFunction.Parameters[0]);

                    parameterType = clrType.AllowClrNullable ? string.Format("{0}?", clrType.GetClrType().Name) : clrType.GetClrType().Name;
                }
                else
                {
                    parameterType = "object";
                }

                var method = new MethodDefinition
                {
                    Attributes =
                    {
                        new MetadataAttribute("DbFunction")
                        {
                            Sets =
                            {
                                new MetadataAttributeSet(project.Version >= EntityFrameworkCoreVersion.Version_3_0 ? "Name" : "FunctionName", string.Format("\"{0}\"", scalarFunction.Name)),
                                new MetadataAttributeSet("Schema",                                                                            string.Format("\"{0}\"", scalarFunction.Schema))
                            }
                        }
                    },
                    IsStatic       = true,
                    Type           = parameterType,
                    AccessModifier = AccessModifier.Public,
                    Name           = project.GetScalarFunctionMethodName(scalarFunction),
                    Lines          =
                    {
                        new CodeLine("throw new Exception();")
                    }
                };

                var parameters = scalarFunction.Parameters.Where(item => !string.IsNullOrEmpty(item.Name)).ToList();

                foreach (var parameter in parameters)
                {
                    var propertyType = project.Database.ResolveDatabaseType(parameter);

                    method.Parameters.Add(new ParameterDefinition(parameterType, project.GetPropertyName(parameter)));
                }

                definition.Methods.Add(method);
            }

            if (projectSelection.Settings.SimplifyDataTypes)
            {
                definition.SimplifyDataTypes();
            }

            return(definition);
        }