♻️ Extract the Storage service to DysonNetwork.Drive microservice

This commit is contained in:
2025-07-06 17:29:26 +08:00
parent 6a3d04af3d
commit 14b79f16f4
71 changed files with 2629 additions and 346 deletions

View File

@ -0,0 +1,127 @@
using System;
using DysonNetwork.Drive.Extensions;
using DysonNetwork.Drive.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Npgsql;
using Npgsql.EntityFrameworkCore.PostgreSQL;
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
namespace DysonNetwork.Drive.Data;
public class AppDatabase : DbContext, IDisposable
{
private readonly IConfiguration _configuration;
public AppDatabase(DbContextOptions<AppDatabase> options, IConfiguration configuration)
: base(options)
{
_configuration = configuration;
}
public DbSet<CloudFile> Files { get; set; } = null!;
public DbSet<CloudFileReference> FileReferences { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseNpgsql(
_configuration.GetConnectionString("DefaultConnection"),
o => o.UseNodaTime()
);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Apply snake_case naming convention for all entities
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
// Replace table names
entity.SetTableName(entity.GetTableName()?.ToSnakeCase());
// Replace column names
foreach (var property in entity.GetProperties())
{
property.SetColumnName(property.Name.ToSnakeCase());
}
// Replace keys
foreach (var key in entity.GetKeys())
{
key.SetName(key.GetName()?.ToSnakeCase());
}
// Replace foreign keys
foreach (var key in entity.GetForeignKeys())
{
key.SetConstraintName(key.GetConstraintName()?.ToSnakeCase());
}
// Replace indexes
foreach (var index in entity.GetIndexes())
{
index.SetDatabaseName(index.GetDatabaseName()?.ToSnakeCase());
}
}
// Configure CloudFile entity
modelBuilder.Entity<CloudFile>(entity =>
{
entity.HasKey(e => e.Id);
entity.HasIndex(e => e.StoragePath).IsUnique();
entity.HasIndex(e => e.ContentHash);
entity.HasIndex(e => e.UploadedById);
entity.HasIndex(e => e.CreatedAt);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
entity.Property(e => e.Name).IsRequired();
entity.Property(e => e.OriginalName).IsRequired();
entity.Property(e => e.MimeType).IsRequired();
entity.Property(e => e.StoragePath).IsRequired();
// Configure JSONB column for ExtendedMetadata
entity.Property(e => e.ExtendedMetadata)
.HasColumnType("jsonb");
// Configure relationships
entity.HasMany(e => e.References)
.WithOne(e => e.File)
.HasForeignKey(e => e.FileId)
.OnDelete(DeleteBehavior.Cascade);
});
// Configure CloudFileReference entity
modelBuilder.Entity<CloudFileReference>(entity =>
{
entity.HasKey(e => e.Id);
entity.HasIndex(e => new { e.ResourceId, e.ResourceType, e.ReferenceType });
entity.HasIndex(e => e.ReferenceId);
entity.Property(e => e.Id).ValueGeneratedOnAdd();
entity.Property(e => e.ResourceId).IsRequired();
entity.Property(e => e.ResourceType).IsRequired();
entity.Property(e => e.ReferenceType).IsRequired();
// Configure JSONB column for Metadata
entity.Property(e => e.Metadata)
.HasColumnType("jsonb");
// Configure relationship with CloudFile
entity.HasOne(e => e.File)
.WithMany(e => e.References)
.HasForeignKey(e => e.FileId)
.OnDelete(DeleteBehavior.Cascade);
});
}
public override void Dispose()
{
base.Dispose();
GC.SuppressFinalize(this);
}
}