kinda working state?

This commit is contained in:
Gwendolyn 2022-11-15 18:07:10 +01:00
parent fcf29ab742
commit a18d10f508
21 changed files with 730 additions and 1058 deletions

View file

@ -1,364 +0,0 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using NetTopologySuite.Geometries;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using labdb.Models;
#nullable disable
namespace labdb.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20221110211959_ModelsInitial")]
partial class ModelsInitial
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("labdb.Models.City", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<Guid>("CountryId")
.HasColumnType("uuid")
.HasColumnName("country_id");
b.Property<string>("EnglishName")
.HasColumnType("text")
.HasColumnName("english_name");
b.Property<Point>("Location")
.IsRequired()
.HasColumnType("geometry")
.HasColumnName("location");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.HasKey("Id")
.HasName("pk_city");
b.HasIndex("CountryId")
.HasDatabaseName("ix_city_country_id");
b.HasIndex(new[] { "EnglishName" }, "english_name")
.IsUnique()
.HasDatabaseName("ix_city_english_name");
b.HasIndex(new[] { "EnglishName" }, "english_name_trgm")
.HasDatabaseName("ix_city_english_name1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "EnglishName" }, "english_name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "EnglishName" }, "english_name_trgm"), new[] { "gin_trgm_ops" });
b.HasIndex(new[] { "Name" }, "name")
.IsUnique()
.HasDatabaseName("ix_city_name");
b.HasIndex(new[] { "Name" }, "name_trgm")
.HasDatabaseName("ix_city_name1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Name" }, "name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Name" }, "name_trgm"), new[] { "gin_trgm_ops" });
b.ToTable("city", (string)null);
});
modelBuilder.Entity("labdb.Models.Country", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.HasKey("Id")
.HasName("pk_country");
b.HasIndex(new[] { "Name" }, "name")
.IsUnique()
.HasDatabaseName("ix_country_name");
b.HasIndex(new[] { "Name" }, "name_trgm")
.HasDatabaseName("ix_country_name1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Name" }, "name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Name" }, "name_trgm"), new[] { "gin_trgm_ops" });
b.ToTable("country", (string)null);
});
modelBuilder.Entity("labdb.Models.Lab", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("AddressCity")
.HasColumnType("text")
.HasColumnName("address_city");
b.Property<string>("AddressLine1")
.HasColumnType("text")
.HasColumnName("address_line1");
b.Property<string>("AddressLine2")
.HasColumnType("text")
.HasColumnName("address_line2");
b.Property<string>("AddressPostcode")
.HasColumnType("text")
.HasColumnName("address_postcode");
b.Property<decimal>("BasicFee")
.HasColumnType("numeric")
.HasColumnName("basic_fee");
b.Property<Guid>("CountryId")
.HasColumnType("uuid")
.HasColumnName("country_id");
b.Property<decimal>("DrawFee")
.HasColumnType("numeric")
.HasColumnName("draw_fee");
b.Property<string>("Email")
.HasColumnType("text")
.HasColumnName("email");
b.Property<Point>("Location")
.HasColumnType("geometry")
.HasColumnName("location");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.Property<string>("Notes")
.HasColumnType("text")
.HasColumnName("notes");
b.Property<string>("Phone")
.HasColumnType("text")
.HasColumnName("phone");
b.Property<bool>("RequiresAppointment")
.HasColumnType("boolean")
.HasColumnName("requires_appointment");
b.Property<bool>("SelfDraw")
.HasColumnType("boolean")
.HasColumnName("self_draw");
b.Property<string>("Website")
.HasColumnType("text")
.HasColumnName("website");
b.HasKey("Id")
.HasName("pk_lab");
b.HasIndex("AddressCity")
.HasDatabaseName("ix_lab_address_city");
b.HasIndex("AddressPostcode")
.HasDatabaseName("ix_lab_address_postcode");
b.HasIndex("BasicFee")
.HasDatabaseName("ix_lab_basic_fee");
b.HasIndex("CountryId")
.HasDatabaseName("ix_lab_country_id");
b.HasIndex("DrawFee")
.HasDatabaseName("ix_lab_draw_fee");
b.HasIndex("RequiresAppointment")
.HasDatabaseName("ix_lab_requires_appointment");
b.HasIndex("SelfDraw")
.HasDatabaseName("ix_lab_self_draw");
b.HasIndex(new[] { "Name" }, "name")
.HasDatabaseName("ix_lab_name");
b.HasIndex(new[] { "Name" }, "name_trgm")
.HasDatabaseName("ix_lab_name");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Name" }, "name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Name" }, "name_trgm"), new[] { "gin_trgm_ops" });
b.ToTable("lab", (string)null);
});
modelBuilder.Entity("labdb.Models.LabTest", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<decimal>("BloodVolume")
.HasColumnType("numeric")
.HasColumnName("blood_volume");
b.Property<Guid>("LabId")
.HasColumnType("uuid")
.HasColumnName("lab_id");
b.Property<string>("Notes")
.HasColumnType("text")
.HasColumnName("notes");
b.Property<decimal>("Price")
.HasColumnType("numeric")
.HasColumnName("price");
b.Property<string>("ServiceDirectoryLink")
.HasColumnType("text")
.HasColumnName("service_directory_link");
b.Property<Guid>("TestId")
.HasColumnType("uuid")
.HasColumnName("test_id");
b.Property<string>("TestMethod")
.HasColumnType("text")
.HasColumnName("test_method");
b.HasKey("Id")
.HasName("pk_lab_test");
b.HasIndex("BloodVolume")
.HasDatabaseName("ix_lab_test_blood_volume");
b.HasIndex("LabId")
.HasDatabaseName("ix_lab_test_lab_id");
b.HasIndex("Price")
.HasDatabaseName("ix_lab_test_price");
b.HasIndex("TestId")
.HasDatabaseName("ix_lab_test_test_id");
b.HasIndex("TestMethod")
.HasDatabaseName("ix_lab_test_test_method");
b.ToTable("lab_test", (string)null);
});
modelBuilder.Entity("labdb.Models.Test", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Abbreviation")
.HasColumnType("text")
.HasColumnName("abbreviation");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("description");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.Property<string>("PubchemLink")
.HasColumnType("text")
.HasColumnName("pubchem_link");
b.HasKey("Id")
.HasName("pk_test");
b.HasIndex(new[] { "Abbreviation" }, "abbreviation")
.IsUnique()
.HasDatabaseName("ix_test_abbreviation");
b.HasIndex(new[] { "Abbreviation" }, "abbreviation_trgm")
.HasDatabaseName("ix_test_abbreviation1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Abbreviation" }, "abbreviation_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Abbreviation" }, "abbreviation_trgm"), new[] { "gin_trgm_ops" });
b.HasIndex(new[] { "Name" }, "name")
.IsUnique()
.HasDatabaseName("ix_test_name");
b.HasIndex(new[] { "Name" }, "name_trgm")
.HasDatabaseName("ix_test_name1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Name" }, "name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Name" }, "name_trgm"), new[] { "gin_trgm_ops" });
b.ToTable("test", (string)null);
});
modelBuilder.Entity("labdb.Models.City", b =>
{
b.HasOne("labdb.Models.Country", "Country")
.WithMany()
.HasForeignKey("CountryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_city_country_country_temp_id");
b.Navigation("Country");
});
modelBuilder.Entity("labdb.Models.Lab", b =>
{
b.HasOne("labdb.Models.Country", "Country")
.WithMany()
.HasForeignKey("CountryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_lab_country_country_id1");
b.Navigation("Country");
});
modelBuilder.Entity("labdb.Models.LabTest", b =>
{
b.HasOne("labdb.Models.Lab", "Lab")
.WithMany()
.HasForeignKey("LabId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_lab_test_lab_lab_id1");
b.HasOne("labdb.Models.Test", "Test")
.WithMany()
.HasForeignKey("TestId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_lab_test_test_test_temp_id");
b.Navigation("Lab");
b.Navigation("Test");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -1,283 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using NetTopologySuite.Geometries;
#nullable disable
namespace labdb.Migrations
{
/// <inheritdoc />
public partial class ModelsInitial : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:PostgresExtension:postgis", ",,");
migrationBuilder.CreateTable(
name: "country",
columns: table => new
{
id = table.Column<Guid>(type: "uuid", nullable: false),
name = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_country", x => x.id);
});
migrationBuilder.CreateTable(
name: "test",
columns: table => new
{
id = table.Column<Guid>(type: "uuid", nullable: false),
name = table.Column<string>(type: "text", nullable: false),
abbreviation = table.Column<string>(type: "text", nullable: true),
description = table.Column<string>(type: "text", nullable: true),
pubchemlink = table.Column<string>(name: "pubchem_link", type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_test", x => x.id);
});
migrationBuilder.CreateTable(
name: "city",
columns: table => new
{
id = table.Column<Guid>(type: "uuid", nullable: false),
name = table.Column<string>(type: "text", nullable: false),
englishname = table.Column<string>(name: "english_name", type: "text", nullable: true),
countryid = table.Column<Guid>(name: "country_id", type: "uuid", nullable: false),
location = table.Column<Point>(type: "geography(POINT,4326)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_city", x => x.id);
table.ForeignKey(
name: "fk_city_country_country_temp_id",
column: x => x.countryid,
principalTable: "country",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "lab",
columns: table => new
{
id = table.Column<Guid>(type: "uuid", nullable: false),
name = table.Column<string>(type: "text", nullable: false),
website = table.Column<string>(type: "text", nullable: true),
phone = table.Column<string>(type: "text", nullable: true),
email = table.Column<string>(type: "text", nullable: true),
addressline1 = table.Column<string>(name: "address_line1", type: "text", nullable: true),
addressline2 = table.Column<string>(name: "address_line2", type: "text", nullable: true),
addresspostcode = table.Column<string>(name: "address_postcode", type: "text", nullable: true),
addresscity = table.Column<string>(name: "address_city", type: "text", nullable: true),
countryid = table.Column<Guid>(name: "country_id", type: "uuid", nullable: false),
location = table.Column<Point>(type: "geography(POINT,4326)", nullable: true),
requiresappointment = table.Column<bool>(name: "requires_appointment", type: "boolean", nullable: false),
selfdraw = table.Column<bool>(name: "self_draw", type: "boolean", nullable: false),
basicfee = table.Column<decimal>(name: "basic_fee", type: "numeric", nullable: false),
drawfee = table.Column<decimal>(name: "draw_fee", type: "numeric", nullable: false),
notes = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_lab", x => x.id);
table.ForeignKey(
name: "fk_lab_country_country_id1",
column: x => x.countryid,
principalTable: "country",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "lab_test",
columns: table => new
{
id = table.Column<Guid>(type: "uuid", nullable: false),
labid = table.Column<Guid>(name: "lab_id", type: "uuid", nullable: false),
testid = table.Column<Guid>(name: "test_id", type: "uuid", nullable: false),
price = table.Column<decimal>(type: "numeric", nullable: false),
servicedirectorylink = table.Column<string>(name: "service_directory_link", type: "text", nullable: true),
bloodvolume = table.Column<decimal>(name: "blood_volume", type: "numeric", nullable: false),
testmethod = table.Column<string>(name: "test_method", type: "text", nullable: true),
notes = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_lab_test", x => x.id);
table.ForeignKey(
name: "fk_lab_test_lab_lab_id1",
column: x => x.labid,
principalTable: "lab",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_lab_test_test_test_temp_id",
column: x => x.testid,
principalTable: "test",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "ix_city_country_id",
table: "city",
column: "country_id");
migrationBuilder.CreateIndex(
name: "ix_city_english_name",
table: "city",
column: "english_name",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_city_english_name1",
table: "city",
column: "english_name")
.Annotation("Npgsql:IndexMethod", "gin")
.Annotation("Npgsql:IndexOperators", new[] { "gin_trgm_ops" });
migrationBuilder.CreateIndex(
name: "ix_city_name",
table: "city",
column: "name",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_city_name1",
table: "city",
column: "name")
.Annotation("Npgsql:IndexMethod", "gin")
.Annotation("Npgsql:IndexOperators", new[] { "gin_trgm_ops" });
migrationBuilder.CreateIndex(
name: "ix_country_name",
table: "country",
column: "name",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_country_name1",
table: "country",
column: "name")
.Annotation("Npgsql:IndexMethod", "gin")
.Annotation("Npgsql:IndexOperators", new[] { "gin_trgm_ops" });
migrationBuilder.CreateIndex(
name: "ix_lab_address_city",
table: "lab",
column: "address_city");
migrationBuilder.CreateIndex(
name: "ix_lab_address_postcode",
table: "lab",
column: "address_postcode");
migrationBuilder.CreateIndex(
name: "ix_lab_basic_fee",
table: "lab",
column: "basic_fee");
migrationBuilder.CreateIndex(
name: "ix_lab_country_id",
table: "lab",
column: "country_id");
migrationBuilder.CreateIndex(
name: "ix_lab_draw_fee",
table: "lab",
column: "draw_fee");
migrationBuilder.CreateIndex(
name: "ix_lab_name",
table: "lab",
column: "name");
migrationBuilder.CreateIndex(
name: "ix_lab_requires_appointment",
table: "lab",
column: "requires_appointment");
migrationBuilder.CreateIndex(
name: "ix_lab_self_draw",
table: "lab",
column: "self_draw");
migrationBuilder.CreateIndex(
name: "ix_lab_test_blood_volume",
table: "lab_test",
column: "blood_volume");
migrationBuilder.CreateIndex(
name: "ix_lab_test_lab_id",
table: "lab_test",
column: "lab_id");
migrationBuilder.CreateIndex(
name: "ix_lab_test_price",
table: "lab_test",
column: "price");
migrationBuilder.CreateIndex(
name: "ix_lab_test_test_id",
table: "lab_test",
column: "test_id");
migrationBuilder.CreateIndex(
name: "ix_lab_test_test_method",
table: "lab_test",
column: "test_method");
migrationBuilder.CreateIndex(
name: "ix_test_abbreviation",
table: "test",
column: "abbreviation",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_test_abbreviation1",
table: "test",
column: "abbreviation")
.Annotation("Npgsql:IndexMethod", "gin")
.Annotation("Npgsql:IndexOperators", new[] { "gin_trgm_ops" });
migrationBuilder.CreateIndex(
name: "ix_test_name",
table: "test",
column: "name",
unique: true);
migrationBuilder.CreateIndex(
name: "ix_test_name1",
table: "test",
column: "name")
.Annotation("Npgsql:IndexMethod", "gin")
.Annotation("Npgsql:IndexOperators", new[] { "gin_trgm_ops" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "city");
migrationBuilder.DropTable(
name: "lab_test");
migrationBuilder.DropTable(
name: "lab");
migrationBuilder.DropTable(
name: "test");
migrationBuilder.DropTable(
name: "country");
}
}
}

View file

@ -1,361 +0,0 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using NetTopologySuite.Geometries;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using labdb.Models;
#nullable disable
namespace labdb.Migrations
{
[DbContext(typeof(AppDbContext))]
partial class AppDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis");
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("labdb.Models.City", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<Guid>("CountryId")
.HasColumnType("uuid")
.HasColumnName("country_id");
b.Property<string>("EnglishName")
.HasColumnType("text")
.HasColumnName("english_name");
b.Property<Point>("Location")
.IsRequired()
.HasColumnType("geometry")
.HasColumnName("location");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.HasKey("Id")
.HasName("pk_city");
b.HasIndex("CountryId")
.HasDatabaseName("ix_city_country_id");
b.HasIndex(new[] { "EnglishName" }, "english_name")
.IsUnique()
.HasDatabaseName("ix_city_english_name");
b.HasIndex(new[] { "EnglishName" }, "english_name_trgm")
.HasDatabaseName("ix_city_english_name1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "EnglishName" }, "english_name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "EnglishName" }, "english_name_trgm"), new[] { "gin_trgm_ops" });
b.HasIndex(new[] { "Name" }, "name")
.IsUnique()
.HasDatabaseName("ix_city_name");
b.HasIndex(new[] { "Name" }, "name_trgm")
.HasDatabaseName("ix_city_name1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Name" }, "name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Name" }, "name_trgm"), new[] { "gin_trgm_ops" });
b.ToTable("city", (string)null);
});
modelBuilder.Entity("labdb.Models.Country", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.HasKey("Id")
.HasName("pk_country");
b.HasIndex(new[] { "Name" }, "name")
.IsUnique()
.HasDatabaseName("ix_country_name");
b.HasIndex(new[] { "Name" }, "name_trgm")
.HasDatabaseName("ix_country_name1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Name" }, "name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Name" }, "name_trgm"), new[] { "gin_trgm_ops" });
b.ToTable("country", (string)null);
});
modelBuilder.Entity("labdb.Models.Lab", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("AddressCity")
.HasColumnType("text")
.HasColumnName("address_city");
b.Property<string>("AddressLine1")
.HasColumnType("text")
.HasColumnName("address_line1");
b.Property<string>("AddressLine2")
.HasColumnType("text")
.HasColumnName("address_line2");
b.Property<string>("AddressPostcode")
.HasColumnType("text")
.HasColumnName("address_postcode");
b.Property<decimal>("BasicFee")
.HasColumnType("numeric")
.HasColumnName("basic_fee");
b.Property<Guid>("CountryId")
.HasColumnType("uuid")
.HasColumnName("country_id");
b.Property<decimal>("DrawFee")
.HasColumnType("numeric")
.HasColumnName("draw_fee");
b.Property<string>("Email")
.HasColumnType("text")
.HasColumnName("email");
b.Property<Point>("Location")
.HasColumnType("geometry")
.HasColumnName("location");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.Property<string>("Notes")
.HasColumnType("text")
.HasColumnName("notes");
b.Property<string>("Phone")
.HasColumnType("text")
.HasColumnName("phone");
b.Property<bool>("RequiresAppointment")
.HasColumnType("boolean")
.HasColumnName("requires_appointment");
b.Property<bool>("SelfDraw")
.HasColumnType("boolean")
.HasColumnName("self_draw");
b.Property<string>("Website")
.HasColumnType("text")
.HasColumnName("website");
b.HasKey("Id")
.HasName("pk_lab");
b.HasIndex("AddressCity")
.HasDatabaseName("ix_lab_address_city");
b.HasIndex("AddressPostcode")
.HasDatabaseName("ix_lab_address_postcode");
b.HasIndex("BasicFee")
.HasDatabaseName("ix_lab_basic_fee");
b.HasIndex("CountryId")
.HasDatabaseName("ix_lab_country_id");
b.HasIndex("DrawFee")
.HasDatabaseName("ix_lab_draw_fee");
b.HasIndex("RequiresAppointment")
.HasDatabaseName("ix_lab_requires_appointment");
b.HasIndex("SelfDraw")
.HasDatabaseName("ix_lab_self_draw");
b.HasIndex(new[] { "Name" }, "name")
.HasDatabaseName("ix_lab_name");
b.HasIndex(new[] { "Name" }, "name_trgm")
.HasDatabaseName("ix_lab_name");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Name" }, "name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Name" }, "name_trgm"), new[] { "gin_trgm_ops" });
b.ToTable("lab", (string)null);
});
modelBuilder.Entity("labdb.Models.LabTest", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<decimal>("BloodVolume")
.HasColumnType("numeric")
.HasColumnName("blood_volume");
b.Property<Guid>("LabId")
.HasColumnType("uuid")
.HasColumnName("lab_id");
b.Property<string>("Notes")
.HasColumnType("text")
.HasColumnName("notes");
b.Property<decimal>("Price")
.HasColumnType("numeric")
.HasColumnName("price");
b.Property<string>("ServiceDirectoryLink")
.HasColumnType("text")
.HasColumnName("service_directory_link");
b.Property<Guid>("TestId")
.HasColumnType("uuid")
.HasColumnName("test_id");
b.Property<string>("TestMethod")
.HasColumnType("text")
.HasColumnName("test_method");
b.HasKey("Id")
.HasName("pk_lab_test");
b.HasIndex("BloodVolume")
.HasDatabaseName("ix_lab_test_blood_volume");
b.HasIndex("LabId")
.HasDatabaseName("ix_lab_test_lab_id");
b.HasIndex("Price")
.HasDatabaseName("ix_lab_test_price");
b.HasIndex("TestId")
.HasDatabaseName("ix_lab_test_test_id");
b.HasIndex("TestMethod")
.HasDatabaseName("ix_lab_test_test_method");
b.ToTable("lab_test", (string)null);
});
modelBuilder.Entity("labdb.Models.Test", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid")
.HasColumnName("id");
b.Property<string>("Abbreviation")
.HasColumnType("text")
.HasColumnName("abbreviation");
b.Property<string>("Description")
.HasColumnType("text")
.HasColumnName("description");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.Property<string>("PubchemLink")
.HasColumnType("text")
.HasColumnName("pubchem_link");
b.HasKey("Id")
.HasName("pk_test");
b.HasIndex(new[] { "Abbreviation" }, "abbreviation")
.IsUnique()
.HasDatabaseName("ix_test_abbreviation");
b.HasIndex(new[] { "Abbreviation" }, "abbreviation_trgm")
.HasDatabaseName("ix_test_abbreviation1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Abbreviation" }, "abbreviation_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Abbreviation" }, "abbreviation_trgm"), new[] { "gin_trgm_ops" });
b.HasIndex(new[] { "Name" }, "name")
.IsUnique()
.HasDatabaseName("ix_test_name");
b.HasIndex(new[] { "Name" }, "name_trgm")
.HasDatabaseName("ix_test_name1");
NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex(new[] { "Name" }, "name_trgm"), "gin");
NpgsqlIndexBuilderExtensions.HasOperators(b.HasIndex(new[] { "Name" }, "name_trgm"), new[] { "gin_trgm_ops" });
b.ToTable("test", (string)null);
});
modelBuilder.Entity("labdb.Models.City", b =>
{
b.HasOne("labdb.Models.Country", "Country")
.WithMany()
.HasForeignKey("CountryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_city_country_country_temp_id");
b.Navigation("Country");
});
modelBuilder.Entity("labdb.Models.Lab", b =>
{
b.HasOne("labdb.Models.Country", "Country")
.WithMany()
.HasForeignKey("CountryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_lab_country_country_id1");
b.Navigation("Country");
});
modelBuilder.Entity("labdb.Models.LabTest", b =>
{
b.HasOne("labdb.Models.Lab", "Lab")
.WithMany()
.HasForeignKey("LabId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_lab_test_lab_lab_id1");
b.HasOne("labdb.Models.Test", "Test")
.WithMany()
.HasForeignKey("TestId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_lab_test_test_test_temp_id");
b.Navigation("Lab");
b.Navigation("Test");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -13,7 +13,6 @@ public class City : EntityBase<CityId>
public CountryId CountryId { get; set; } = null!;
public Country Country { get; set; } = null!;
public Point Location { get; set; } = null!;
}
public class CityConfiguration : EntityBaseConfiguration<City, CityId>

View file

@ -1,3 +1,4 @@
using System.ComponentModel;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
@ -7,7 +8,14 @@ public record CountryId : EntityIdBase<CountryId>;
public class Country : EntityBase<CountryId>
{
public string Name { get; set; } = null!;
public string Name { get; init; } = null!;
public string EnglishName { get; init; } = null!;
public string Code { get; init; } = null!;
public List<City> Cities { get; set; } = new();
public List<Lab> Labs { get; set; } = new();
}
public class CountryConfiguration : EntityBaseConfiguration<Country, CountryId>
@ -16,7 +24,12 @@ public class CountryConfiguration : EntityBaseConfiguration<Country, CountryId>
{
base.Configure(builder);
builder.HasIndex(x => x.Name,"name").IsUnique();
builder.HasIndex(x => x.Name, "name").IsUnique();
builder.HasIndex(x => x.Name, "name_trgm").HasMethod("gin").HasOperators("gin_trgm_ops");
builder.HasData(
new Country { Name = "Deutschland", EnglishName = "Germany", Code = "DE" },
new Country { Name = "TEST", EnglishName = "TEST COUNTRY", Code = "TEST" }
);
}
}

View file

@ -1,4 +1,6 @@
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
@ -18,24 +20,24 @@ public abstract record EntityIdBase<TId> : EntityIdBase
{
return new TId { Value = Guid.Parse(guid) };
}
public static bool TryParse(string guid, [NotNullWhen(true)] out TId? value)
{
value = null;
if (!Guid.TryParse(guid, out var result))
{
return false;
}
value = new TId
{
Value = result
};
return true;
}
public static TId FromGuid(Guid id)
{
return new TId { Value = id };
@ -79,11 +81,11 @@ public static class EntityIdJsonConverterExtensions
{
var types = assembly.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(EntityIdBase)));
foreach (var type in types)
{
var converterType = typeof(EntityIdJsonConverter<>).MakeGenericType(type);
var converter = (JsonConverter) Activator.CreateInstance(converterType)!;
var converter = (JsonConverter)Activator.CreateInstance(converterType)!;
options.Converters.Add(converter);
}
}

View file

@ -1,3 +1,4 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using NetTopologySuite.Geometries;
@ -8,7 +9,7 @@ public record LabId : EntityIdBase<LabId>;
public class Lab : EntityBase<LabId>
{
public string Name { get; set; } = null!;
public string Name { get; set; } = "";
public string? Website { get; set; }
public string? Phone { get; set; }
public string? Email { get; set; }
@ -16,8 +17,10 @@ public class Lab : EntityBase<LabId>
public string? AddressLine1 { get; set; }
public string? AddressLine2 { get; set; }
public string? AddressPostcode { get; set; }
public string? AddressCity { get; set; }
public CountryId CountryId { get; set; } = null!;
public Country Country { get; set; } = null!;
public Point? Location { get; set; }
@ -27,6 +30,8 @@ public class Lab : EntityBase<LabId>
public decimal BasicFee { get; set; }
public decimal DrawFee { get; set; }
public string? Notes { get; set; }
public List<TestOffer> TestOffers { get; set; } = new();
}
public class LabConfiguration : EntityBaseConfiguration<Lab, LabId>
@ -38,7 +43,6 @@ public class LabConfiguration : EntityBaseConfiguration<Lab, LabId>
builder.HasIndex(x => x.Name, "name");
builder.HasIndex(x => x.Name, "name_trgm").HasMethod("gin").HasOperators("gin_trgm_ops");
builder.HasIndex(x => x.AddressPostcode);
builder.HasIndex(x => x.AddressCity);
builder.HasIndex(x => x.RequiresAppointment);
builder.HasIndex(x => x.SelfDraw);
builder.HasIndex(x => x.BasicFee);

View file

@ -1,4 +1,3 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
@ -12,7 +11,10 @@ public class Test : EntityBase<TestId>
public string? Abbreviation { get; set; }
public string? Description { get; set; }
public string? PubchemLink { get; set; }
public List<TestOffer> TestOffers { get; set; } = new();
public List<TestSynonym> Synonyms { get; set; } = new();
}
public class TestConfiguration : EntityBaseConfiguration<Test, TestId>

View file

@ -3,9 +3,9 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace labdb.Models;
public record LabTestId : EntityIdBase<LabTestId>;
public record TestOfferId : EntityIdBase<TestOfferId>;
public class LabTest : EntityBase<LabTestId>
public class TestOffer : EntityBase<TestOfferId>
{
public LabId LabId { get; init; } = null!;
public Lab Lab { get; init; } = null!;
@ -18,9 +18,9 @@ public class LabTest : EntityBase<LabTestId>
public string? Notes { get; set; }
}
public class LabTestConfiguration : EntityBaseConfiguration<LabTest, LabTestId>
public class LabTestConfiguration : EntityBaseConfiguration<TestOffer, TestOfferId>
{
public override void Configure(EntityTypeBuilder<LabTest> builder)
public override void Configure(EntityTypeBuilder<TestOffer> builder)
{
base.Configure(builder);

24
Models/TestSynonym.cs Normal file
View file

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace labdb.Models;
public record TestSynonymId : EntityIdBase<TestSynonymId>;
public class TestSynonym : EntityBase<TestSynonymId>
{
public TestId TestId { get; init; } = null!;
public Test Test { get; init; } = null!;
public string Name { get; set; } = null!;
}
public class TestSynonymConfiguration : EntityBaseConfiguration<TestSynonym, TestSynonymId>
{
public override void Configure(EntityTypeBuilder<TestSynonym> builder)
{
base.Configure(builder);
builder.HasIndex(x => x.Name, "name").IsUnique();
builder.HasIndex(x => x.Name, "name_trgm").HasMethod("gin").HasOperators("gin_trgm_ops");
}
}

View file

@ -6,4 +6,4 @@
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
<p><em>Not implemented</em></p>
<p><em>Loading...</em></p>

257
Pages/Labs/Edit.razor Normal file
View file

@ -0,0 +1,257 @@
@page "/labs/add"
@page "/labs/{id:guid}"
@using Microsoft.EntityFrameworkCore
@using Microsoft.AspNetCore.Components
<PageTitle>@Title</PageTitle>
<h1>@Title</h1>
@if (Lab != null)
{
<EditForm Model="@Lab" OnValidSubmit="@HandleValidSubmit" class="row g-3 mb-3">
<DataAnnotationsValidator/>
<ValidationSummary/>
<div class="col-lg-6 row g-lg-3 g-md-2 g-1 h-100">
<div class="col-12 form-floating">
<InputText @bind-Value="Lab.Name" id="inputName" class="form-control"/>
<label for="inputName">Name</label>
</div>
<div class="col-md-4 form-floating">
<InputText @bind-Value="Lab.Website" id="inputWebsite" class="form-control"/>
<label for="inputWebsite">Website</label>
</div>
<div class="col-md-4 form-floating">
<InputText @bind-Value="Lab.Phone" id="inputPhone" class="form-control"/>
<label for="inputPhone">Phone</label>
</div>
<div class="col-md-4 form-floating">
<InputText @bind-Value="Lab.Email" id="inputEmail" class="form-control"/>
<label for="inputEmail">Email</label>
</div>
<div class="col-12">
<label for="inputCountry">
Country
</label>
<InputSelect @bind-Value="SelectedCountryId" id="inputCountry" class="form-select">
@foreach (var country in Countries)
{
<option value="@country.Id.Value">@country.Name (@country.EnglishName)</option>
}
</InputSelect>
</div>
<div class="col-12 form-floating">
<InputText @bind-Value="Lab.AddressLine1" id="inputAddressLine1" class="form-control"/>
<label for="inputAddressLine1">Address line 1</label>
</div>
<div class="col-12 form-floating">
<InputText @bind-Value="Lab.AddressLine2" id="inputAddressLine2" class="form-control"/>
<label for="inputAddressLine2">Address line 2</label>
</div>
<div class="col-md-6 form-floating">
<InputText @bind-Value="Lab.AddressPostcode" id="inputPostcode" class="form-control"/>
<label for="inputPostcode">Postcode</label>
</div>
<div class="col-md-6 form-floating">
<InputText @bind-Value="Lab.AddressCity" id="inputCity" class="form-control"/>
<label for="inputCity">City</label>
</div>
<div class="col-md-6">
<div class="form-check">
<InputCheckbox @bind-Value="Lab.RequiresAppointment" id="inputRequiresAppointment" class="form-check-input"/>
<label for="inputRequiresAppointment" class="form-check-label">Requires appointment</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check">
<InputCheckbox @bind-Value="Lab.SelfDraw" id="inputSelfDraw" class="form-check-input"/>
<label for="inputSelfDraw" class="form-check-label">Self draw blood</label>
</div>
</div>
<div class="col-md-6 form-floating">
<InputNumber @bind-Value="Lab.BasicFee" id="inputBasicFee" class="form-control"/>
<label for="inputBasicFee">Basic fee (€)</label>
</div>
<div class="col-md-6 form-floating">
<InputNumber @bind-Value="Lab.DrawFee" id="inputDrawFee" class="form-control"/>
<label for="inputDrawFee">Blood draw fee (€)</label>
</div>
<div class="col-12 form-floating">
<InputTextArea @bind-Value="Lab.Notes" id="inputNotes" class="form-control" style="height: 100px"/>
<label for="inputNotes">Notes</label>
</div>
</div>
<div class="col-lg-6 row g-lg-3 g-md-2 g-1">
@foreach (var test in Tests)
{
var offer = Lab.TestOffers.FirstOrDefault(x => x.TestId == test.Id);
<div class="card">
<div class="card-body">
@if (offer == null)
{
<button class="btn btn-success float-end" type="button" @onclick="() => AddOffer(test)">Add</button>
}
else
{
<button class="btn btn-danger float-end" type="button" @onclick="() => RemoveOffer(offer)">Remove</button>
}
<h5 class="card-title">@test.Abbreviation</h5>
<h6 class="card-subtitle mb-2 text-muted">@test.Name</h6>
@if (offer != null)
{
<div class="row g-1">
<div class="col-md-6 form-floating">
<InputNumber @bind-Value="offer.Price" id="@($"inputPrice-{offer.Id.Value}")" class="form-control"/>
<label for="@($"inputPrice-{offer.Id.Value}")">Price (€)</label>
</div>
<div class="col-md-6 form-floating">
<InputNumber @bind-Value="offer.BloodVolume" id="@($"inputBloodVolume-{offer.Id.Value}")" class="form-control"/>
<label for="@($"inputBloodVolume-{offer.Id.Value}")">Blood Volume (mL)</label>
</div>
<div class="col-12 form-floating">
<InputText @bind-Value="offer.ServiceDirectoryLink" id="@($"inputServiceDirectoryLink-{offer.Id.Value}")" class="form-control"/>
<label for="@($"inputServiceDirectoryLink-{offer.Id.Value}")">Leistungsverzeichnis-Link</label>
</div>
<div class="col-12 form-floating">
<InputText @bind-Value="offer.TestMethod" id="@($"inputTestMethod-{offer.Id.Value}")" class="form-control"/>
<label for="@($"inputTestMethod-{offer.Id.Value}")">Method</label>
</div>
<div class="col-12 form-floating">
<InputTextArea @bind-Value="offer.Notes" id="@($"inputNotes-{offer.Id.Value}")" class="form-control"/>
<label for="@($"inputNotes-{offer.Id.Value}")">Notes</label>
</div>
</div>
}
</div>
</div>
}
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn btn-danger float-end" @onclick="() => ShowDeleteModal = true">Delete</button>
</div>
</EditForm>
}
else
{
<h1>NOT FOUND</h1>
}
@if (ShowDeleteModal)
{
<div class="modal show" tabindex="-1" style="display: block;">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Really delete this lab?</h5>
<button type="button" class="btn-close" @onclick="() => ShowDeleteModal = false" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Deleted labs cannot be recovered.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @onclick="() => ShowDeleteModal = false">Abort</button>
<button type="button" class="btn btn-danger" @onclick="DeleteLab">Delete</button>
</div>
</div>
</div>
</div>
<div class="modal-backdrop fade show"></div>
}
@code {
[Inject]
public NavigationManager NavigationManager { get; set; } = null!;
[Inject]
public IDbContextFactory<AppDbContext> DbContextFactory { get; set; } = null!;
[Parameter]
public Guid? Id { get; set; }
private Lab? Lab { get; set; }
private List<Country> Countries { get; set; } = new();
private List<Test> Tests { get; set; } = new();
private string Title => Id == null ? "Add lab" : "Edit lab";
private Guid SelectedCountryId
{
get => Lab?.CountryId.Value ?? Guid.Empty;
set => Lab!.CountryId = CountryId.FromGuid(value);
}
private List<TestOffer> NewOffers { get; set; } = new();
private List<TestOffer> RemovedOffers { get; set; } = new();
private bool ShowDeleteModal { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
using var ctx = DbContextFactory.CreateDbContext();
Countries = ctx.Set<Country>().ToList();
Tests = ctx.Set<Test>().ToList();
if (Id != null)
{
Lab = ctx.Set<Lab>()
.Include(x => x.TestOffers)
.First(x => x.Id == LabId.FromGuid(Id.Value));
Lab.Country = null!; // this seems super hacky, wtf
}
else
{
Lab = new Lab { CountryId = Countries.First().Id };
}
}
private void HandleValidSubmit()
{
using var ctx = DbContextFactory.CreateDbContext();
if (Id == null)
{
ctx.Add(Lab!);
}
else
{
ctx.Update(Lab!);
}
ctx.AddRange(NewOffers);
ctx.RemoveRange(RemovedOffers);
ctx.SaveChanges();
NavigationManager.NavigateTo("/labs");
}
private void AddOffer(Test test)
{
var offer = new TestOffer { TestId = test.Id };
Lab!.TestOffers.Add(offer);
NewOffers.Add(offer);
}
private void RemoveOffer(TestOffer offer)
{
Lab!.TestOffers.Remove(offer);
RemovedOffers.Add(offer);
}
private void DeleteLab()
{
using var ctx = DbContextFactory.CreateDbContext();
ctx.RemoveRange(Lab!.TestOffers);
ctx.Remove(Lab!);
ctx.SaveChanges();
NavigationManager.NavigateTo("/labs");
}
}

94
Pages/Labs/List.razor Normal file
View file

@ -0,0 +1,94 @@
@page "/labs"
@using Microsoft.EntityFrameworkCore
<PageTitle>Labs</PageTitle>
<h1>Labs</h1>
<a href="/labs/add" class="btn btn-primary">Add new</a>
<table class="table table-striped">
<thead>
<tr>
<td>Name</td>
<td>Location</td>
</tr>
</thead>
<tbody>
@foreach (var lab in Labs)
{
<tr>
<td>
<a href="@($"/labs/{lab.Id.Value}")">@lab.Name</a>
</td>
<td>
@if (!string.IsNullOrEmpty(lab.AddressCity))
{
<span>@lab.AddressCity</span>@(", ")
}
<span>@lab.Country.Name</span>
</td>
</tr>
}
</tbody>
</table>
<div>
<ul class="pagination">
@for (var i = 1; i <= TotalPages; i++)
{
var p = i;
<li class="page-item @(i == CurrentPage ? "active" : "")">
<a class="page-link" href="@($"/labs?page={p}")">@p</a>
</li>
}
</ul>
</div>
@code {
[Inject]
public IDbContextFactory<AppDbContext> DbContextFactory { get; set; } = null!;
[Parameter]
[SupplyParameterFromQuery(Name = "page")]
public int? CurrentPage { get; set; }
private int Count { get; set; }
private int PageSize { get; set; } = 10;
private int TotalPages => (int)Math.Ceiling(decimal.Divide(Count, PageSize));
private List<Lab> Labs { get; set; } = new();
private void Load()
{
using var ctx = DbContextFactory.CreateDbContext();
Count = ctx.Set<Lab>().Count();
var page = CurrentPage ?? 1;
Labs = ctx.Set<Lab>()
.OrderBy(x => x.Id)
.Skip((page - 1) * PageSize)
.Take(PageSize)
.Include(x => x.Country)
.ToList();
}
protected override void OnInitialized()
{
base.OnInitialized();
Load();
}
protected override void OnParametersSet()
{
base.OnParametersSet();
Load();
}
}

181
Pages/Tests/Edit.razor Normal file
View file

@ -0,0 +1,181 @@
@page "/tests/add"
@page "/tests/{id:guid}"
@using Microsoft.EntityFrameworkCore
@using Microsoft.AspNetCore.Components
<PageTitle>@Title</PageTitle>
<h1>@Title</h1>
@if (Test != null)
{
<EditForm Model="@Test" OnValidSubmit="@HandleValidSubmit" class="row g-3 mb-3">
<DataAnnotationsValidator/>
<ValidationSummary/>
<div class="col-lg-6 row g-lg-3 g-md-2 g-1 h-100">
<div class="col-md-8 form-floating">
<InputText @bind-Value="Test.Name" id="inputName" class="form-control"/>
<label for="inputName">Name</label>
</div>
<div class="col-md-4 form-floating">
<InputText @bind-Value="Test.Abbreviation" id="inputAbbreviation" class="form-control"/>
<label for="inputAbbreviation">Abbreviation</label>
</div>
<div class="col-12 form-floating">
<InputText @bind-Value="Test.PubchemLink" id="inputPubchem" class="form-control"/>
<label for="inputPubchem">PubChem</label>
</div>
</div>
<div class="col-lg-6 row g-lg-3 g-md-2 g-1">
<h3>Synonyms</h3>
@foreach (var synonym in Test.Synonyms)
{
<div class="input-group">
<InputText @bind-Value="synonym.Name" class="form-control"/>
<button class="btn btn-outline-danger" @onclick="() => DeleteSynonym(synonym)" type="button">x</button>
</div>
}
<div class="input-group">
<input type="text" class="form-control" id="testNewSynonymInput" @bind="NewSynonym" @bind:event="oninput" @onkeydown="NewSynonymKeydown" @onblur="NewSynonymBlur"/>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary">Save</button>
<button type="button" class="btn btn-danger float-end" @onclick="() => ShowDeleteModal = true">Delete</button>
</div>
</EditForm>
}
else
{
<h1>NOT FOUND</h1>
}
@if (ShowDeleteModal)
{
<div class="modal show" tabindex="-1" style="display: block;">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Really delete this test?</h5>
<button type="button" class="btn-close" @onclick="() => ShowDeleteModal = false" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Deleted tests cannot be recovered, and all lab test offers for this test are deleted as well.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @onclick="() => ShowDeleteModal = false">Abort</button>
<button type="button" class="btn btn-danger" @onclick="DeleteTest">Delete</button>
</div>
</div>
</div>
</div>
<div class="modal-backdrop fade show"></div>
}
@code {
[Inject]
public NavigationManager NavigationManager { get; set; } = null!;
[Inject]
public IDbContextFactory<AppDbContext> DbContextFactory { get; set; } = null!;
[Inject]
public IJSRuntime Js { get; set; } = null!;
[Parameter]
public Guid? Id { get; set; }
private Test? Test { get; set; }
private string Title => Id == null ? "Add test" : "Edit test";
private string NewSynonym { get; set; } = "";
private List<TestSynonym> NewSynonyms { get; set; } = new();
private List<TestSynonym> RemovedSynonyms { get; set; } = new();
private bool ShowDeleteModal { get; set; }
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Js.InvokeVoidAsync("PreventEnterKey", "testNewSynonymInput");
}
}
protected override void OnInitialized()
{
base.OnInitialized();
using var ctx = DbContextFactory.CreateDbContext();
if (Id != null)
{
Test = ctx.Set<Test>()
.Include(x => x.Synonyms)
.First(x => x.Id == TestId.FromGuid(Id.Value));
}
else
{
Test = new Test();
}
}
private void HandleValidSubmit()
{
using var ctx = DbContextFactory.CreateDbContext();
if (Id == null)
{
ctx.Add(Test!);
}
else
{
ctx.Update(Test!);
}
ctx.AddRange(NewSynonyms);
ctx.RemoveRange(RemovedSynonyms);
ctx.SaveChanges();
NavigationManager.NavigateTo("/tests");
}
private void AddSynonym()
{
if (NewSynonym == "") return;
var synonym = new TestSynonym { Name = NewSynonym };
Test!.Synonyms.Add(synonym);
NewSynonyms.Add(synonym);
NewSynonym = "";
}
private void NewSynonymKeydown(KeyboardEventArgs e)
{
if (e.Code == "Enter")
{
AddSynonym();
}
}
private void NewSynonymBlur()
{
AddSynonym();
}
private void DeleteSynonym(TestSynonym synonym)
{
Test!.Synonyms.Remove(synonym);
RemovedSynonyms.Add(synonym);
}
private void DeleteTest()
{
using var ctx = DbContextFactory.CreateDbContext();
ctx.RemoveRange(Test!.TestOffers);
ctx.Remove(Test!);
ctx.SaveChanges();
NavigationManager.NavigateTo("/tests");
}
}

94
Pages/Tests/List.razor Normal file
View file

@ -0,0 +1,94 @@
@page "/tests"
@using Microsoft.EntityFrameworkCore
<PageTitle>Tests</PageTitle>
<h1>Tests</h1>
<a href="/tests/add" class="btn btn-primary">Add new</a>
<table class="table table-striped">
<thead>
<tr>
<td>Name</td>
<td>Abbreviation</td>
<td>Synonyms</td>
</tr>
</thead>
<tbody>
@foreach (var test in Tests)
{
<tr>
<td>
<a href="@($"/tests/{test.Id.Value}")">@test.Name</a>
</td>
<td>
@test.Abbreviation
</td>
<td>
@(string.Join(", ", test.Synonyms.Select(x => x.Name).ToArray()))
</td>
</tr>
}
</tbody>
</table>
<div>
<ul class="pagination">
@for (var i = 1; i <= TotalPages; i++)
{
var p = i;
<li class="page-item @(i == CurrentPage ? "active" : "")">
<a class="page-link" href="@($"/labs?page={p}")">@p</a>
</li>
}
</ul>
</div>
@code {
[Inject]
public IDbContextFactory<AppDbContext> DbContextFactory { get; set; } = null!;
[Parameter]
[SupplyParameterFromQuery(Name = "page")]
public int? CurrentPage { get; set; }
private int Count { get; set; }
private int PageSize { get; set; } = 10;
private int TotalPages => (int)Math.Ceiling(decimal.Divide(Count, PageSize));
private List<Test> Tests { get; set; } = new();
private void Load()
{
using var ctx = DbContextFactory.CreateDbContext();
Count = ctx.Set<Lab>().Count();
var page = CurrentPage ?? 1;
Tests = ctx.Set<Test>()
.OrderBy(x => x.Id)
.Skip((page - 1) * PageSize)
.Take(PageSize)
.Include(x => x.Synonyms)
.ToList();
}
protected override void OnInitialized()
{
base.OnInitialized();
Load();
}
protected override void OnParametersSet()
{
base.OnParametersSet();
Load();
}
}

View file

@ -5,28 +5,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="labdb.styles.css" rel="stylesheet" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<base href="~/"/>
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css"/>
<link href="css/site.css" rel="stylesheet"/>
<link href="labdb.styles.css" rel="stylesheet"/>
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/>
</head>
<body>
@RenderBody()
@RenderBody()
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
<script src="_framework/blazor.server.js"></script>
<script src="js/site.js"></script>
</body>
</html>
</html>

View file

@ -10,18 +10,13 @@
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
<NavLink class="nav-link" href="/labs" Match="NavLinkMatch.All">
Labs
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
<NavLink class="nav-link" href="/tests">
Tests
</NavLink>
</div>
</nav>

View file

@ -8,3 +8,5 @@
@using Microsoft.JSInterop
@using labdb
@using labdb.Shared
@using labdb.Models

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
@ -18,4 +18,8 @@
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations" />
</ItemGroup>
</Project>

View file

@ -1,4 +1,4 @@
# datenbankschema
# datenbankschemaLocaition<tbody></@fore@for(eachvar lab in labs) {}<tr></tr><td>
labs:

8
wwwroot/js/site.js Normal file
View file

@ -0,0 +1,8 @@
window.PreventEnterKey = (id) => {
document.getElementById(id).addEventListener('keydown', function (event) {
if (event.keyCode === 13) {
event.preventDefault();
return false;
}
})
};