diff --git a/DXApp.TemplateKitProject/Data/AppDbContext.cs b/DXApp.TemplateKitProject/Data/AppDbContext.cs index eb0c94d..9aab324 100644 --- a/DXApp.TemplateKitProject/Data/AppDbContext.cs +++ b/DXApp.TemplateKitProject/Data/AppDbContext.cs @@ -6,4 +6,27 @@ namespace DXApp.TemplateKitProject.Data; public class AppDbContext(DbContextOptions options) : DbContext(options) { public DbSet ZugferdInvoices { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity(entity => + { + // Index für Performance-Optimierung der Rechnungsliste + entity.HasIndex(e => e.ImportedAt) + .HasDatabaseName("IX_ZugferdInvoices_ImportedAt"); + + // Index für Duplikatprüfung + entity.HasIndex(e => new { e.InvoiceNumber, e.SellerTaxId }) + .HasDatabaseName("IX_ZugferdInvoices_InvoiceNumber_SellerTaxId"); + + // Decimal-Präzision explizit festlegen (behebt EF Core Warnung) + entity.Property(e => e.TotalAmount) + .HasColumnType("decimal(18,2)"); + + entity.Property(e => e.TaxAmount) + .HasColumnType("decimal(18,2)"); + }); + } } \ No newline at end of file diff --git a/DXApp.TemplateKitProject/Migrations/20260602114123_AddPerformanceIndexes.Designer.cs b/DXApp.TemplateKitProject/Migrations/20260602114123_AddPerformanceIndexes.Designer.cs new file mode 100644 index 0000000..e9339f3 --- /dev/null +++ b/DXApp.TemplateKitProject/Migrations/20260602114123_AddPerformanceIndexes.Designer.cs @@ -0,0 +1,91 @@ +// +using System; +using DXApp.TemplateKitProject.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DXApp.TemplateKitProject.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20260602114123_AddPerformanceIndexes")] + partial class AddPerformanceIndexes + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("DXApp.TemplateKitProject.Models.ZugferdInvoice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BuyerName") + .HasColumnType("nvarchar(max)"); + + b.Property("CurrencyCode") + .HasColumnType("nvarchar(max)"); + + b.Property("GuidelineId") + .HasColumnType("nvarchar(max)"); + + b.Property("Iban") + .HasColumnType("nvarchar(max)"); + + b.Property("ImportedAt") + .HasColumnType("datetime2"); + + b.Property("InvoiceDate") + .HasColumnType("datetime2"); + + b.Property("InvoiceNumber") + .HasColumnType("nvarchar(450)"); + + b.Property("RawXml") + .HasColumnType("nvarchar(max)"); + + b.Property("ResultFilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("SellerName") + .HasColumnType("nvarchar(max)"); + + b.Property("SellerTaxId") + .HasColumnType("nvarchar(450)"); + + b.Property("SourceType") + .HasColumnType("nvarchar(max)"); + + b.Property("TaxAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalAmount") + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("ImportedAt") + .HasDatabaseName("IX_ZugferdInvoices_ImportedAt"); + + b.HasIndex("InvoiceNumber", "SellerTaxId") + .HasDatabaseName("IX_ZugferdInvoices_InvoiceNumber_SellerTaxId"); + + b.ToTable("ZugferdInvoices"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DXApp.TemplateKitProject/Migrations/20260602114123_AddPerformanceIndexes.cs b/DXApp.TemplateKitProject/Migrations/20260602114123_AddPerformanceIndexes.cs new file mode 100644 index 0000000..2b67fa0 --- /dev/null +++ b/DXApp.TemplateKitProject/Migrations/20260602114123_AddPerformanceIndexes.cs @@ -0,0 +1,72 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DXApp.TemplateKitProject.Migrations +{ + /// + public partial class AddPerformanceIndexes : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "SellerTaxId", + table: "ZugferdInvoices", + type: "nvarchar(450)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "InvoiceNumber", + table: "ZugferdInvoices", + type: "nvarchar(450)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + + migrationBuilder.CreateIndex( + name: "IX_ZugferdInvoices_ImportedAt", + table: "ZugferdInvoices", + column: "ImportedAt"); + + migrationBuilder.CreateIndex( + name: "IX_ZugferdInvoices_InvoiceNumber_SellerTaxId", + table: "ZugferdInvoices", + columns: new[] { "InvoiceNumber", "SellerTaxId" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_ZugferdInvoices_ImportedAt", + table: "ZugferdInvoices"); + + migrationBuilder.DropIndex( + name: "IX_ZugferdInvoices_InvoiceNumber_SellerTaxId", + table: "ZugferdInvoices"); + + migrationBuilder.AlterColumn( + name: "SellerTaxId", + table: "ZugferdInvoices", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(450)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "InvoiceNumber", + table: "ZugferdInvoices", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(450)", + oldNullable: true); + } + } +} diff --git a/DXApp.TemplateKitProject/Migrations/AppDbContextModelSnapshot.cs b/DXApp.TemplateKitProject/Migrations/AppDbContextModelSnapshot.cs index cf75b6c..c8cfaee 100644 --- a/DXApp.TemplateKitProject/Migrations/AppDbContextModelSnapshot.cs +++ b/DXApp.TemplateKitProject/Migrations/AppDbContextModelSnapshot.cs @@ -49,7 +49,7 @@ namespace DXApp.TemplateKitProject.Migrations .HasColumnType("datetime2"); b.Property("InvoiceNumber") - .HasColumnType("nvarchar(max)"); + .HasColumnType("nvarchar(450)"); b.Property("RawXml") .HasColumnType("nvarchar(max)"); @@ -61,7 +61,7 @@ namespace DXApp.TemplateKitProject.Migrations .HasColumnType("nvarchar(max)"); b.Property("SellerTaxId") - .HasColumnType("nvarchar(max)"); + .HasColumnType("nvarchar(450)"); b.Property("SourceType") .HasColumnType("nvarchar(max)"); @@ -74,6 +74,12 @@ namespace DXApp.TemplateKitProject.Migrations b.HasKey("Id"); + b.HasIndex("ImportedAt") + .HasDatabaseName("IX_ZugferdInvoices_ImportedAt"); + + b.HasIndex("InvoiceNumber", "SellerTaxId") + .HasDatabaseName("IX_ZugferdInvoices_InvoiceNumber_SellerTaxId"); + b.ToTable("ZugferdInvoices"); }); #pragma warning restore 612, 618 diff --git a/DXApp.TemplateKitProject/Models/ZugferdInvoiceListDto.cs b/DXApp.TemplateKitProject/Models/ZugferdInvoiceListDto.cs new file mode 100644 index 0000000..05cc7c3 --- /dev/null +++ b/DXApp.TemplateKitProject/Models/ZugferdInvoiceListDto.cs @@ -0,0 +1,22 @@ +namespace DXApp.TemplateKitProject.Models; + +/// +/// Lightweight DTO für die Rechnungsliste (ohne RawXml für bessere Performance) +/// +public class ZugferdInvoiceListDto +{ + public int Id { get; set; } + public string InvoiceNumber { get; set; } = string.Empty; + public DateTime InvoiceDate { get; set; } + public string SellerName { get; set; } = string.Empty; + public string SellerTaxId { get; set; } = string.Empty; + public string BuyerName { get; set; } = string.Empty; + public decimal TotalAmount { get; set; } + public decimal TaxAmount { get; set; } + public string CurrencyCode { get; set; } = string.Empty; + public string Iban { get; set; } = string.Empty; + public DateTime ImportedAt { get; set; } + public string SourceType { get; set; } = string.Empty; + public string ResultFilePath { get; set; } = string.Empty; + public string GuidelineId { get; set; } = string.Empty; +} diff --git a/DXApp.TemplateKitProject/Pages/Invoices/Index.cshtml b/DXApp.TemplateKitProject/Pages/Invoices/Index.cshtml index aad760a..6bafd73 100644 --- a/DXApp.TemplateKitProject/Pages/Invoices/Index.cshtml +++ b/DXApp.TemplateKitProject/Pages/Invoices/Index.cshtml @@ -12,7 +12,7 @@ } else { - @(Html.DevExtreme().DataGrid() + @(Html.DevExtreme().DataGrid() .DataSource(Model.Invoices) .KeyExpr("Id") .ShowBorders(true) diff --git a/DXApp.TemplateKitProject/Pages/Invoices/Index.cshtml.cs b/DXApp.TemplateKitProject/Pages/Invoices/Index.cshtml.cs index c49647a..86d718b 100644 --- a/DXApp.TemplateKitProject/Pages/Invoices/Index.cshtml.cs +++ b/DXApp.TemplateKitProject/Pages/Invoices/Index.cshtml.cs @@ -7,12 +7,30 @@ namespace DXApp.TemplateKitProject.Pages.Invoices; public class IndexModel(AppDbContext db) : PageModel { - public List Invoices { get; private set; } = []; + public List Invoices { get; private set; } = []; public async Task OnGetAsync() { Invoices = await db.ZugferdInvoices .OrderByDescending(i => i.ImportedAt) + .Select(i => new ZugferdInvoiceListDto + { + Id = i.Id, + InvoiceNumber = i.InvoiceNumber, + InvoiceDate = i.InvoiceDate, + SellerName = i.SellerName, + SellerTaxId = i.SellerTaxId, + BuyerName = i.BuyerName, + TotalAmount = i.TotalAmount, + TaxAmount = i.TaxAmount, + CurrencyCode = i.CurrencyCode, + Iban = i.Iban, + ImportedAt = i.ImportedAt, + SourceType = i.SourceType, + ResultFilePath = i.ResultFilePath, + GuidelineId = i.GuidelineId + // RawXml wird NICHT geladen ? Performance-Optimierung! + }) .ToListAsync(); } }