From 384fceb0471e80b536b68f4adf2b8ec6bd1a3466 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Wed, 11 Feb 2026 11:26:50 -0500 Subject: [PATCH] feat: add local database and file export infrastructure Add EF Core DbContext with ExportRecord and BomItem entities for tracking export history locally. Add FileExportService for saving DXF and PDF files to a configurable output folder. Co-Authored-By: Claude Opus 4.6 --- ExportDXF/Data/ExportDxfDbContext.cs | 61 +++++++++++++++++++++ ExportDXF/Models/ExportRecord.cs | 17 ++++++ ExportDXF/Services/FileExportService.cs | 72 +++++++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 ExportDXF/Data/ExportDxfDbContext.cs create mode 100644 ExportDXF/Models/ExportRecord.cs create mode 100644 ExportDXF/Services/FileExportService.cs diff --git a/ExportDXF/Data/ExportDxfDbContext.cs b/ExportDXF/Data/ExportDxfDbContext.cs new file mode 100644 index 0000000..d949690 --- /dev/null +++ b/ExportDXF/Data/ExportDxfDbContext.cs @@ -0,0 +1,61 @@ +using ExportDXF.Models; +using Microsoft.EntityFrameworkCore; +using System.Configuration; + +namespace ExportDXF.Data +{ + public class ExportDxfDbContext : DbContext + { + public DbSet ExportRecords { get; set; } + public DbSet BomItems { get; set; } + + public ExportDxfDbContext() : base() + { + } + + public ExportDxfDbContext(DbContextOptions options) : base(options) + { + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + var connectionString = ConfigurationManager.ConnectionStrings["ExportDxfDb"]?.ConnectionString + ?? "Server=localhost;Database=ExportDxfDb;Trusted_Connection=True;TrustServerCertificate=True;"; + optionsBuilder.UseSqlServer(connectionString); + } + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.Id); + entity.Property(e => e.DrawingNumber).HasMaxLength(100); + entity.Property(e => e.SourceFilePath).HasMaxLength(500); + entity.Property(e => e.OutputFolder).HasMaxLength(500); + entity.Property(e => e.ExportedBy).HasMaxLength(100); + + entity.HasMany(e => e.BomItems) + .WithOne(b => b.ExportRecord) + .HasForeignKey(b => b.ExportRecordId) + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.ID); + entity.Property(e => e.ItemNo).HasMaxLength(50); + entity.Property(e => e.PartNo).HasMaxLength(100); + entity.Property(e => e.Description).HasMaxLength(500); + entity.Property(e => e.PartName).HasMaxLength(200); + entity.Property(e => e.ConfigurationName).HasMaxLength(100); + entity.Property(e => e.Material).HasMaxLength(100); + entity.Property(e => e.CutTemplateName).HasMaxLength(100); + }); + } + } +} diff --git a/ExportDXF/Models/ExportRecord.cs b/ExportDXF/Models/ExportRecord.cs new file mode 100644 index 0000000..77c201c --- /dev/null +++ b/ExportDXF/Models/ExportRecord.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; + +namespace ExportDXF.Models +{ + public class ExportRecord + { + public int Id { get; set; } + public string DrawingNumber { get; set; } + public string SourceFilePath { get; set; } + public string OutputFolder { get; set; } + public DateTime ExportedAt { get; set; } + public string ExportedBy { get; set; } + + public virtual ICollection BomItems { get; set; } = new List(); + } +} diff --git a/ExportDXF/Services/FileExportService.cs b/ExportDXF/Services/FileExportService.cs new file mode 100644 index 0000000..9e42f6d --- /dev/null +++ b/ExportDXF/Services/FileExportService.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; + +namespace ExportDXF.Services +{ + public interface IFileExportService + { + string OutputFolder { get; } + string SaveDxfFile(string sourcePath, string drawingNumber, string itemNo); + string SavePdfFile(string sourcePath, string drawingNumber); + void EnsureOutputFolderExists(); + } + + public class FileExportService : IFileExportService + { + public string OutputFolder { get; } + + public FileExportService(string outputFolder) + { + OutputFolder = outputFolder ?? throw new ArgumentNullException(nameof(outputFolder)); + EnsureOutputFolderExists(); + } + + public void EnsureOutputFolderExists() + { + if (!Directory.Exists(OutputFolder)) + { + Directory.CreateDirectory(OutputFolder); + } + } + + public string SaveDxfFile(string sourcePath, string drawingNumber, string itemNo) + { + if (string.IsNullOrEmpty(sourcePath)) + throw new ArgumentNullException(nameof(sourcePath)); + + var fileName = !string.IsNullOrEmpty(drawingNumber) && !string.IsNullOrEmpty(itemNo) + ? $"{drawingNumber} PT{itemNo}.dxf" + : Path.GetFileName(sourcePath); + + var destPath = Path.Combine(OutputFolder, fileName); + + // If source and dest are the same, skip copy + if (!string.Equals(sourcePath, destPath, StringComparison.OrdinalIgnoreCase)) + { + File.Copy(sourcePath, destPath, overwrite: true); + } + + return destPath; + } + + public string SavePdfFile(string sourcePath, string drawingNumber) + { + if (string.IsNullOrEmpty(sourcePath)) + throw new ArgumentNullException(nameof(sourcePath)); + + var fileName = !string.IsNullOrEmpty(drawingNumber) + ? $"{drawingNumber}.pdf" + : Path.GetFileName(sourcePath); + + var destPath = Path.Combine(OutputFolder, fileName); + + // If source and dest are the same, skip copy + if (!string.Equals(sourcePath, destPath, StringComparison.OrdinalIgnoreCase)) + { + File.Copy(sourcePath, destPath, overwrite: true); + } + + return destPath; + } + } +}