diff --git a/Dockerfile b/Dockerfile index 0a5787c..02c77ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,9 @@ COPY . . # Compile and pack server as self contained app RUN dotnet publish /src/Nesteo.Server/Nesteo.Server.csproj -c Release -o /app --self-contained --runtime debian-x64 +# Compile and pack sample data generation tool as self contained app +RUN dotnet publish /src/Nesteo.Server.SampleDataGenerator/Nesteo.Server.SampleDataGenerator.csproj -c Release -o /app --runtime debian-x64 + ### Build final image diff --git a/Nesteo.Server.SampleDataGenerator/Nesteo.Server.SampleDataGenerator.csproj b/Nesteo.Server.SampleDataGenerator/Nesteo.Server.SampleDataGenerator.csproj new file mode 100644 index 0000000..018e7e0 --- /dev/null +++ b/Nesteo.Server.SampleDataGenerator/Nesteo.Server.SampleDataGenerator.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp3.0 + 8 + + + + + + + diff --git a/Nesteo.Server.SampleDataGenerator/Program.cs b/Nesteo.Server.SampleDataGenerator/Program.cs new file mode 100644 index 0000000..0900a6e --- /dev/null +++ b/Nesteo.Server.SampleDataGenerator/Program.cs @@ -0,0 +1,127 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Nesteo.Server.Data; +using Nesteo.Server.Data.Entities; +using Nesteo.Server.Data.Entities.Identity; +using Nesteo.Server.Data.Enums; + +namespace Nesteo.Server.SampleDataGenerator +{ + public static class Program + { + public static async Task Main(string[] args) + { + // Create host + IHost host = Server.Program.CreateHostBuilder(args).Build(); + await Server.Program.PrepareHostAsync(host).ConfigureAwait(false); + + // Request database context + NesteoDbContext dbContext = host.Services.GetRequiredService(); + + // Safety check + Console.Write("Do you want to fill the database with sample data? Please type 'yes': "); + if (Console.ReadLine()?.ToLower() != "yes") + return; + Console.Write("Do you really want to do this? This will DELETE all existing data! Please type 'yes': "); + if (Console.ReadLine()?.ToLower() != "yes") + return; + + Console.WriteLine("Clearing database..."); + + // Clear database + dbContext.Regions.RemoveRange(dbContext.Regions); + dbContext.Owners.RemoveRange(dbContext.Owners); + dbContext.Species.RemoveRange(dbContext.Species); + dbContext.NestingBoxes.RemoveRange(dbContext.NestingBoxes); + dbContext.ReservedIdSpaces.RemoveRange(dbContext.ReservedIdSpaces); + dbContext.Inspections.RemoveRange(dbContext.Inspections); + await dbContext.SaveChangesAsync().ConfigureAwait(false); + + Console.WriteLine("Generating sample data..."); + + var random = new Random(); + UserEntity user = await dbContext.Users.FirstOrDefaultAsync().ConfigureAwait(false); + if (user == null) + { + Console.WriteLine("Please run the server first to make sure that at least one user exists."); + return; + } + + // Generate regions + Console.WriteLine("Generating regions..."); + await dbContext.Regions.AddRangeAsync( + Enumerable.Range(1, 20).Select(i => new RegionEntity { Name = $"Owner {i}", NestingBoxIdPrefix = ((char)('A' + (i - 1))).ToString() })) + .ConfigureAwait(false); + + // Generate owners + Console.WriteLine("Generating owners..."); + await dbContext.Owners.AddRangeAsync(Enumerable.Range(1, 15).Select(i => new OwnerEntity { Name = $"Owner {i}" })).ConfigureAwait(false); + + // Generate species + Console.WriteLine("Generating species..."); + await dbContext.Species.AddRangeAsync(Enumerable.Range(1, 50).Select(i => new SpeciesEntity { Name = $"Species {i}" })).ConfigureAwait(false); + + // Generate nesting boxes + Console.WriteLine("Generating nesting boxes..."); + await dbContext.NestingBoxes.AddRangeAsync(Enumerable.Range(1, 400).Select(i => { + RegionEntity region = dbContext.Regions.Local.GetRandomOrDefault(); + + return new NestingBoxEntity { + Id = $"{region.NestingBoxIdPrefix}{i:00000}", + Region = region, + OldId = random.Next(10) >= 5 ? "Old ID" : null, + ForeignId = random.Next(10) >= 5 ? "Foreign ID" : null, + CoordinateLongitude = 9.724372 + region.Id + (random.NextDouble() - 0.5) / 100, + CoordinateLatitude = 52.353092 + (random.NextDouble() - 0.5) / 100, + HangUpDate = DateTime.UtcNow.AddMonths(-6 - random.Next(24)), + HangUpUser = user, + Owner = dbContext.Owners.Local.GetRandomOrDefault(), + Material = (Material)random.Next(4), + HoleSize = (HoleSize)random.Next(7), + ImageFileName = null, + Comment = "This is a generated nesting box for testing purposes." + }; + })).ConfigureAwait(false); + + // Generate inspections + Console.WriteLine("Generating inspections..."); + await dbContext.Inspections.AddRangeAsync(Enumerable.Range(1, 2000).Select(i => { + NestingBoxEntity nestingBox = dbContext.NestingBoxes.Local.GetRandomOrDefault(); + + return new InspectionEntity { + NestingBox = nestingBox, + InspectionDate = nestingBox.HangUpDate.GetValueOrDefault().AddMonths(random.Next(6)), + InspectedByUser = user, + HasBeenCleaned = false, + Condition = (Condition)random.Next(3), + JustRepaired = false, + Occupied = true, + ContainsEggs = true, + EggCount = random.Next(6), + ChickCount = random.Next(1, 4), + RingedChickCount = 1, + AgeInDays = random.Next(6), + FemaleParentBirdDiscovery = (ParentBirdDiscovery)random.Next(4), + MaleParentBirdDiscovery = (ParentBirdDiscovery)random.Next(4), + Species = dbContext.Species.Local.GetRandomOrDefault(), + ImageFileName = null, + Comment = "This is a generated inspection for testing purposes." + }; + })).ConfigureAwait(false); + + Console.WriteLine("Saving sample data..."); + + // Save changes + await dbContext.SaveChangesAsync().ConfigureAwait(false); + + Console.WriteLine("Done."); + } + + private static T GetRandomOrDefault(this LocalView localView) where T : class => localView.OrderBy(r => Guid.NewGuid()).FirstOrDefault(); + } +} diff --git a/Nesteo.Server.sln b/Nesteo.Server.sln index 22fddf5..3d29dfb 100644 --- a/Nesteo.Server.sln +++ b/Nesteo.Server.sln @@ -17,6 +17,8 @@ ProjectSection(SolutionItems) = preProject sample.env = sample.env EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nesteo.Server.SampleDataGenerator", "Nesteo.Server.SampleDataGenerator\Nesteo.Server.SampleDataGenerator.csproj", "{CB1814DC-8726-4158-8C7C-D7B86F93ABE8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,5 +33,9 @@ Global {A58836B0-4FCA-46A2-BDDF-4FB8D67C2162}.Debug|Any CPU.Build.0 = Debug|Any CPU {A58836B0-4FCA-46A2-BDDF-4FB8D67C2162}.Release|Any CPU.ActiveCfg = Release|Any CPU {A58836B0-4FCA-46A2-BDDF-4FB8D67C2162}.Release|Any CPU.Build.0 = Release|Any CPU + {CB1814DC-8726-4158-8C7C-D7B86F93ABE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB1814DC-8726-4158-8C7C-D7B86F93ABE8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB1814DC-8726-4158-8C7C-D7B86F93ABE8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB1814DC-8726-4158-8C7C-D7B86F93ABE8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Nesteo.Server/Data/Entities/NestingBoxEntity.cs b/Nesteo.Server/Data/Entities/NestingBoxEntity.cs index 90b4d26..38b7278 100644 --- a/Nesteo.Server/Data/Entities/NestingBoxEntity.cs +++ b/Nesteo.Server/Data/Entities/NestingBoxEntity.cs @@ -19,11 +19,9 @@ public class NestingBoxEntity : IEntity [Required] public RegionEntity Region { get; set; } - [Required] [StringLength(100, MinimumLength = 2)] public string OldId { get; set; } - [Required] [StringLength(100, MinimumLength = 2)] public string ForeignId { get; set; } diff --git a/Nesteo.Server/Data/Enums/Condition.cs b/Nesteo.Server/Data/Enums/Condition.cs index b4de27e..8914f9e 100644 --- a/Nesteo.Server/Data/Enums/Condition.cs +++ b/Nesteo.Server/Data/Enums/Condition.cs @@ -6,8 +6,8 @@ namespace Nesteo.Server.Data.Enums [JsonConverter(typeof(StringEnumConverter))] public enum Condition { - Good, - NeedsRepair, - NeedsReplacement + Good = 0, + NeedsRepair = 1, + NeedsReplacement = 2 } } diff --git a/Nesteo.Server/Migrations/20191014235003_NestingBoxRequiredIdsChanges.Designer.cs b/Nesteo.Server/Migrations/20191014235003_NestingBoxRequiredIdsChanges.Designer.cs new file mode 100644 index 0000000..4682516 --- /dev/null +++ b/Nesteo.Server/Migrations/20191014235003_NestingBoxRequiredIdsChanges.Designer.cs @@ -0,0 +1,548 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Nesteo.Server.Data; + +namespace Nesteo.Server.Migrations +{ + [DbContext(typeof(NesteoDbContext))] + [Migration("20191014235003_NestingBoxRequiredIdsChanges")] + partial class NestingBoxRequiredIdsChanges + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserTokens"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.Identity.RoleEntity", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.Identity.UserEntity", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.InspectionEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AgeInDays") + .HasColumnType("int"); + + b.Property("ChickCount") + .HasColumnType("int"); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("Condition") + .HasColumnType("int"); + + b.Property("ContainsEggs") + .HasColumnType("bit"); + + b.Property("EggCount") + .HasColumnType("int"); + + b.Property("FemaleParentBirdDiscovery") + .HasColumnType("int"); + + b.Property("HasBeenCleaned") + .HasColumnType("bit"); + + b.Property("ImageFileName") + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.Property("InspectedByUserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("InspectionDate") + .HasColumnType("datetime(6)"); + + b.Property("JustRepaired") + .HasColumnType("bit"); + + b.Property("LastUpdated") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("MaleParentBirdDiscovery") + .HasColumnType("int"); + + b.Property("NestingBoxId") + .IsRequired() + .HasColumnType("varchar(6)"); + + b.Property("Occupied") + .HasColumnType("bit"); + + b.Property("RingedChickCount") + .HasColumnType("int"); + + b.Property("SpeciesId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("InspectedByUserId"); + + b.HasIndex("NestingBoxId"); + + b.HasIndex("SpeciesId"); + + b.ToTable("Inspections"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.NestingBoxEntity", b => + { + b.Property("Id") + .HasColumnType("varchar(6)") + .HasMaxLength(6); + + b.Property("Comment") + .HasColumnType("longtext"); + + b.Property("CoordinateLatitude") + .HasColumnType("double"); + + b.Property("CoordinateLongitude") + .HasColumnType("double"); + + b.Property("ForeignId") + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.Property("HangUpDate") + .HasColumnType("datetime(6)"); + + b.Property("HangUpUserId") + .HasColumnType("varchar(255)"); + + b.Property("HoleSize") + .HasColumnType("int"); + + b.Property("ImageFileName") + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.Property("LastUpdated") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); + + b.Property("Material") + .HasColumnType("int"); + + b.Property("OldId") + .HasColumnType("varchar(100)") + .HasMaxLength(100); + + b.Property("OwnerId") + .HasColumnType("int"); + + b.Property("RegionId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("HangUpUserId"); + + b.HasIndex("OwnerId"); + + b.HasIndex("RegionId"); + + b.ToTable("NestingBoxes"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.OwnerEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(255)") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Owners"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.RegionEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(255)") + .HasMaxLength(255); + + b.Property("NestingBoxIdPrefix") + .HasColumnType("varchar(10)") + .HasMaxLength(10); + + b.HasKey("Id"); + + b.ToTable("Regions"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.ReservedIdSpaceEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("FirstNestingBoxIdWithoutPrefix") + .HasColumnType("int"); + + b.Property("LastNestingBoxIdWithoutPrefix") + .HasColumnType("int"); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("RegionId") + .HasColumnType("int"); + + b.Property("ReservationDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.HasIndex("RegionId"); + + b.ToTable("ReservedIdSpaces"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.SpeciesEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(255)") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Species"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Nesteo.Server.Data.Entities.Identity.RoleEntity", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Nesteo.Server.Data.Entities.Identity.RoleEntity", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.InspectionEntity", b => + { + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", "InspectedByUser") + .WithMany() + .HasForeignKey("InspectedByUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Nesteo.Server.Data.Entities.NestingBoxEntity", "NestingBox") + .WithMany("Inspections") + .HasForeignKey("NestingBoxId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Nesteo.Server.Data.Entities.SpeciesEntity", "Species") + .WithMany("Inspections") + .HasForeignKey("SpeciesId"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.NestingBoxEntity", b => + { + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", "HangUpUser") + .WithMany() + .HasForeignKey("HangUpUserId"); + + b.HasOne("Nesteo.Server.Data.Entities.OwnerEntity", "Owner") + .WithMany("NestingBoxes") + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Nesteo.Server.Data.Entities.RegionEntity", "Region") + .WithMany("NestingBoxes") + .HasForeignKey("RegionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.ReservedIdSpaceEntity", b => + { + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Nesteo.Server.Data.Entities.RegionEntity", "Region") + .WithMany() + .HasForeignKey("RegionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Nesteo.Server/Migrations/20191014235003_NestingBoxRequiredIdsChanges.cs b/Nesteo.Server/Migrations/20191014235003_NestingBoxRequiredIdsChanges.cs new file mode 100644 index 0000000..eec5c36 --- /dev/null +++ b/Nesteo.Server/Migrations/20191014235003_NestingBoxRequiredIdsChanges.cs @@ -0,0 +1,47 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Nesteo.Server.Migrations +{ + public partial class NestingBoxRequiredIdsChanges : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "OldId", + table: "NestingBoxes", + maxLength: 100, + nullable: true, + oldClrType: typeof(string), + oldMaxLength: 100); + + migrationBuilder.AlterColumn( + name: "ForeignId", + table: "NestingBoxes", + maxLength: 100, + nullable: true, + oldClrType: typeof(string), + oldMaxLength: 100); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "OldId", + table: "NestingBoxes", + maxLength: 100, + nullable: false, + oldClrType: typeof(string), + oldMaxLength: 100, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "ForeignId", + table: "NestingBoxes", + maxLength: 100, + nullable: false, + oldClrType: typeof(string), + oldMaxLength: 100, + oldNullable: true); + } + } +} diff --git a/Nesteo.Server/Migrations/NesteoDbContextModelSnapshot.cs b/Nesteo.Server/Migrations/NesteoDbContextModelSnapshot.cs index 9b23210..b641a25 100644 --- a/Nesteo.Server/Migrations/NesteoDbContextModelSnapshot.cs +++ b/Nesteo.Server/Migrations/NesteoDbContextModelSnapshot.cs @@ -2,6 +2,7 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Nesteo.Server.Data; namespace Nesteo.Server.Migrations @@ -13,20 +14,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("ProductVersion", "3.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); - b.Property("ClaimType"); + b.Property("ClaimType") + .HasColumnType("longtext"); - b.Property("ClaimValue"); + b.Property("ClaimValue") + .HasColumnType("longtext"); b.Property("RoleId") - .IsRequired(); + .IsRequired() + .HasColumnType("varchar(255)"); b.HasKey("Id"); @@ -38,14 +43,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); - b.Property("ClaimType"); + b.Property("ClaimType") + .HasColumnType("longtext"); - b.Property("ClaimValue"); + b.Property("ClaimValue") + .HasColumnType("longtext"); b.Property("UserId") - .IsRequired(); + .IsRequired() + .HasColumnType("varchar(255)"); b.HasKey("Id"); @@ -56,14 +65,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.Property("LoginProvider"); + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); - b.Property("ProviderKey"); + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); - b.Property("ProviderDisplayName"); + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); b.Property("UserId") - .IsRequired(); + .IsRequired() + .HasColumnType("varchar(255)"); b.HasKey("LoginProvider", "ProviderKey"); @@ -74,9 +87,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { - b.Property("UserId"); + b.Property("UserId") + .HasColumnType("varchar(255)"); - b.Property("RoleId"); + b.Property("RoleId") + .HasColumnType("varchar(255)"); b.HasKey("UserId", "RoleId"); @@ -87,64 +102,185 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.Property("UserId"); + b.Property("UserId") + .HasColumnType("varchar(255)"); - b.Property("LoginProvider"); + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); - b.Property("Name"); + b.Property("Name") + .HasColumnType("varchar(255)"); - b.Property("Value"); + b.Property("Value") + .HasColumnType("longtext"); b.HasKey("UserId", "LoginProvider", "Name"); b.ToTable("UserTokens"); }); + modelBuilder.Entity("Nesteo.Server.Data.Entities.Identity.RoleEntity", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("Nesteo.Server.Data.Entities.Identity.UserEntity", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Email") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasColumnType("varchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("Users"); + }); + modelBuilder.Entity("Nesteo.Server.Data.Entities.InspectionEntity", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); - b.Property("AgeInDays"); + b.Property("AgeInDays") + .HasColumnType("int"); - b.Property("ChickCount"); + b.Property("ChickCount") + .HasColumnType("int"); - b.Property("Comment"); + b.Property("Comment") + .HasColumnType("longtext"); - b.Property("Condition"); + b.Property("Condition") + .HasColumnType("int"); - b.Property("ContainsEggs"); + b.Property("ContainsEggs") + .HasColumnType("bit"); - b.Property("EggCount"); + b.Property("EggCount") + .HasColumnType("int"); - b.Property("FemaleParentBirdDiscovery"); + b.Property("FemaleParentBirdDiscovery") + .HasColumnType("int"); - b.Property("HasBeenCleaned"); + b.Property("HasBeenCleaned") + .HasColumnType("bit"); b.Property("ImageFileName") + .HasColumnType("varchar(100)") .HasMaxLength(100); b.Property("InspectedByUserId") - .IsRequired(); + .IsRequired() + .HasColumnType("varchar(255)"); - b.Property("InspectionDate"); + b.Property("InspectionDate") + .HasColumnType("datetime(6)"); - b.Property("JustRepaired"); + b.Property("JustRepaired") + .HasColumnType("bit"); b.Property("LastUpdated") .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate(); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); - b.Property("MaleParentBirdDiscovery"); + b.Property("MaleParentBirdDiscovery") + .HasColumnType("int"); b.Property("NestingBoxId") - .IsRequired(); + .IsRequired() + .HasColumnType("varchar(6)"); - b.Property("Occupied"); + b.Property("Occupied") + .HasColumnType("bit"); - b.Property("RingedChickCount"); + b.Property("RingedChickCount") + .HasColumnType("int"); - b.Property("SpeciesId"); + b.Property("SpeciesId") + .HasColumnType("int"); b.HasKey("Id"); @@ -160,40 +296,52 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Nesteo.Server.Data.Entities.NestingBoxEntity", b => { b.Property("Id") + .HasColumnType("varchar(6)") .HasMaxLength(6); - b.Property("Comment"); + b.Property("Comment") + .HasColumnType("longtext"); - b.Property("CoordinateLatitude"); + b.Property("CoordinateLatitude") + .HasColumnType("double"); - b.Property("CoordinateLongitude"); + b.Property("CoordinateLongitude") + .HasColumnType("double"); b.Property("ForeignId") - .IsRequired() + .HasColumnType("varchar(100)") .HasMaxLength(100); - b.Property("HangUpDate"); + b.Property("HangUpDate") + .HasColumnType("datetime(6)"); - b.Property("HangUpUserId"); + b.Property("HangUpUserId") + .HasColumnType("varchar(255)"); - b.Property("HoleSize"); + b.Property("HoleSize") + .HasColumnType("int"); b.Property("ImageFileName") + .HasColumnType("varchar(100)") .HasMaxLength(100); b.Property("LastUpdated") .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate(); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); - b.Property("Material"); + b.Property("Material") + .HasColumnType("int"); b.Property("OldId") - .IsRequired() + .HasColumnType("varchar(100)") .HasMaxLength(100); - b.Property("OwnerId"); + b.Property("OwnerId") + .HasColumnType("int"); - b.Property("RegionId"); + b.Property("RegionId") + .HasColumnType("int"); b.HasKey("Id"); @@ -209,10 +357,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Nesteo.Server.Data.Entities.OwnerEntity", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); b.Property("Name") .IsRequired() + .HasColumnType("varchar(255)") .HasMaxLength(255); b.HasKey("Id"); @@ -223,13 +373,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Nesteo.Server.Data.Entities.RegionEntity", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); b.Property("Name") .IsRequired() + .HasColumnType("varchar(255)") .HasMaxLength(255); b.Property("NestingBoxIdPrefix") + .HasColumnType("varchar(10)") .HasMaxLength(10); b.HasKey("Id"); @@ -240,18 +393,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Nesteo.Server.Data.Entities.ReservedIdSpaceEntity", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); - b.Property("FirstNestingBoxIdWithoutPrefix"); + b.Property("FirstNestingBoxIdWithoutPrefix") + .HasColumnType("int"); - b.Property("LastNestingBoxIdWithoutPrefix"); + b.Property("LastNestingBoxIdWithoutPrefix") + .HasColumnType("int"); b.Property("OwnerId") - .IsRequired(); + .IsRequired() + .HasColumnType("varchar(255)"); - b.Property("RegionId"); + b.Property("RegionId") + .HasColumnType("int"); - b.Property("ReservationDate"); + b.Property("ReservationDate") + .HasColumnType("datetime(6)"); b.HasKey("Id"); @@ -265,10 +424,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Nesteo.Server.Data.Entities.SpeciesEntity", b => { b.Property("Id") - .ValueGeneratedOnAdd(); + .ValueGeneratedOnAdd() + .HasColumnType("int"); b.Property("Name") .IsRequired() + .HasColumnType("varchar(255)") .HasMaxLength(255); b.HasKey("Id"); @@ -276,141 +437,70 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Species"); }); - modelBuilder.Entity("Nesteo.Server.Data.Identity.NesteoRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); - - b.Property("Name") - .HasMaxLength(256); - - b.Property("NormalizedName") - .HasMaxLength(256); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasName("RoleNameIndex"); - - b.ToTable("Roles"); - }); - - modelBuilder.Entity("Nesteo.Server.Data.Identity.NesteoUser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd(); - - b.Property("AccessFailedCount"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken(); - - b.Property("Email") - .HasMaxLength(256); - - b.Property("EmailConfirmed"); - - b.Property("FirstName") - .IsRequired(); - - b.Property("LastName") - .IsRequired(); - - b.Property("LockoutEnabled"); - - b.Property("LockoutEnd"); - - b.Property("NormalizedEmail") - .HasMaxLength(256); - - b.Property("NormalizedUserName") - .HasMaxLength(256); - - b.Property("PasswordHash"); - - b.Property("PhoneNumber"); - - b.Property("PhoneNumberConfirmed"); - - b.Property("SecurityStamp"); - - b.Property("TwoFactorEnabled"); - - b.Property("UserName") - .HasMaxLength(256); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasName("UserNameIndex"); - - b.ToTable("Users"); - }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { - b.HasOne("Nesteo.Server.Data.Identity.NesteoRole") + b.HasOne("Nesteo.Server.Data.Entities.Identity.RoleEntity", null) .WithMany() .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => { - b.HasOne("Nesteo.Server.Data.Identity.NesteoUser") + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { - b.HasOne("Nesteo.Server.Data.Identity.NesteoUser") + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { - b.HasOne("Nesteo.Server.Data.Identity.NesteoRole") + b.HasOne("Nesteo.Server.Data.Entities.Identity.RoleEntity", null) .WithMany() .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); - b.HasOne("Nesteo.Server.Data.Identity.NesteoUser") + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { - b.HasOne("Nesteo.Server.Data.Identity.NesteoUser") + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", null) .WithMany() .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Nesteo.Server.Data.Entities.InspectionEntity", b => { - b.HasOne("Nesteo.Server.Data.Identity.NesteoUser", "InspectedByUser") + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", "InspectedByUser") .WithMany() .HasForeignKey("InspectedByUserId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.HasOne("Nesteo.Server.Data.Entities.NestingBoxEntity", "NestingBox") - .WithMany() + .WithMany("Inspections") .HasForeignKey("NestingBoxId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.HasOne("Nesteo.Server.Data.Entities.SpeciesEntity", "Species") .WithMany("Inspections") @@ -419,32 +509,36 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Nesteo.Server.Data.Entities.NestingBoxEntity", b => { - b.HasOne("Nesteo.Server.Data.Identity.NesteoUser", "HangUpUser") + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", "HangUpUser") .WithMany() .HasForeignKey("HangUpUserId"); b.HasOne("Nesteo.Server.Data.Entities.OwnerEntity", "Owner") .WithMany("NestingBoxes") .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.HasOne("Nesteo.Server.Data.Entities.RegionEntity", "Region") .WithMany("NestingBoxes") .HasForeignKey("RegionId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); modelBuilder.Entity("Nesteo.Server.Data.Entities.ReservedIdSpaceEntity", b => { - b.HasOne("Nesteo.Server.Data.Identity.NesteoUser", "Owner") + b.HasOne("Nesteo.Server.Data.Entities.Identity.UserEntity", "Owner") .WithMany() .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.HasOne("Nesteo.Server.Data.Entities.RegionEntity", "Region") .WithMany() .HasForeignKey("RegionId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); #pragma warning restore 612, 618 } diff --git a/Nesteo.Server/Program.cs b/Nesteo.Server/Program.cs index cbaf3d1..ca2623b 100644 --- a/Nesteo.Server/Program.cs +++ b/Nesteo.Server/Program.cs @@ -13,6 +13,18 @@ public static async Task Main(string[] args) { IHost host = CreateHostBuilder(args).Build(); + // Prepare host + await PrepareHostAsync(host).ConfigureAwait(false); + + // Run application + await host.RunAsync().ConfigureAwait(false); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + + public static Task PrepareHostAsync(IHost host) + { // Validate and prepare the AutoMapper configuration IConfigurationProvider mapperConfigurationProvider = host.Services.GetRequiredService(); #if DEBUG @@ -20,11 +32,7 @@ public static async Task Main(string[] args) #endif mapperConfigurationProvider.CompileMappings(); - // Run application - await host.RunAsync().ConfigureAwait(false); + return Task.CompletedTask; } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); } } diff --git a/README.md b/README.md index e9abe10..f2de30f 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,13 @@ These have been set to the following values on first server start: **Password:** Admin123 +### Sample data generation + +You can use the following command to fill the database with generated sample data: +``` +docker-compose exec nesteo-server /app/Nesteo.Server.SampleDataGenerator +``` + ## Setup of a development environment #### Install the .Net Core SDK diff --git a/database.sql b/database.sql index f952de2..dfb0cc5 100644 --- a/database.sql +++ b/database.sql @@ -557,7 +557,53 @@ BEGIN IF NOT EXISTS(SELECT 1 FROM `__EFMigrationsHistory` WHERE `MigrationId` = '20190920015448_InitialCreate') THEN INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) - VALUES ('20190920015448_InitialCreate', '2.2.6-servicing-10079'); + VALUES ('20190920015448_InitialCreate', '3.0.0'); + + END IF; +END // +DELIMITER ; +CALL MigrationsScript(); +DROP PROCEDURE MigrationsScript; + + +DROP PROCEDURE IF EXISTS MigrationsScript; +DELIMITER // +CREATE PROCEDURE MigrationsScript() +BEGIN + IF NOT EXISTS(SELECT 1 FROM `__EFMigrationsHistory` WHERE `MigrationId` = '20191014235003_NestingBoxRequiredIdsChanges') THEN + + ALTER TABLE `NestingBoxes` MODIFY COLUMN `OldId` varchar(100) NULL; + + END IF; +END // +DELIMITER ; +CALL MigrationsScript(); +DROP PROCEDURE MigrationsScript; + + +DROP PROCEDURE IF EXISTS MigrationsScript; +DELIMITER // +CREATE PROCEDURE MigrationsScript() +BEGIN + IF NOT EXISTS(SELECT 1 FROM `__EFMigrationsHistory` WHERE `MigrationId` = '20191014235003_NestingBoxRequiredIdsChanges') THEN + + ALTER TABLE `NestingBoxes` MODIFY COLUMN `ForeignId` varchar(100) NULL; + + END IF; +END // +DELIMITER ; +CALL MigrationsScript(); +DROP PROCEDURE MigrationsScript; + + +DROP PROCEDURE IF EXISTS MigrationsScript; +DELIMITER // +CREATE PROCEDURE MigrationsScript() +BEGIN + IF NOT EXISTS(SELECT 1 FROM `__EFMigrationsHistory` WHERE `MigrationId` = '20191014235003_NestingBoxRequiredIdsChanges') THEN + + INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) + VALUES ('20191014235003_NestingBoxRequiredIdsChanges', '3.0.0'); END IF; END //