🗑️ Clean up the cloud file table unused fields

This commit is contained in:
2026-01-11 23:58:37 +08:00
parent de1175bdc7
commit 6d5303f99c
9 changed files with 26 additions and 11 deletions

View File

@@ -42,9 +42,11 @@ public class UsageService(AppDatabase db)
PoolName = p.Name,
UsageBytes = fileQuery
.Where(f => f.PoolId == p.Id)
.Include(f => f.Object)
.Sum(f => f.Size),
Cost = fileQuery
.Where(f => f.PoolId == p.Id)
.Include(f => f.Object)
.Sum(f => f.Size) / 1024.0 / 1024.0 *
(p.BillingConfig.CostMultiplier ?? 1.0),
FileCount = fileQuery
@@ -80,6 +82,7 @@ public class UsageService(AppDatabase db)
.AsQueryable();
var usageBytes = await fileQuery
.Include(f => f.Object)
.SumAsync(f => f.Size);
var fileCount = await fileQuery
@@ -106,6 +109,7 @@ public class UsageService(AppDatabase db)
.Where(f => f.PoolId.HasValue)
.Where(f => !f.IsMarkedRecycle)
.Include(f => f.Pool)
.Include(f => f.Object)
.Where(f => !f.ExpiredAt.HasValue || f.ExpiredAt > now)
.Select(f => new
{

View File

@@ -216,6 +216,7 @@ public class FileIndexController(
&& f.IsMarkedRecycle == recycled
&& !db.FileIndexes.Any(fi => fi.FileId == f.Id && fi.AccountId == accountId)
)
.Include(f => f.Object)
.AsQueryable();
// Apply sorting

View File

@@ -167,6 +167,7 @@ public class FileIndexService(AppDatabase db)
return await db.FileIndexes
.Where(fi => fi.AccountId == accountId)
.Include(fi => fi.File)
.ThenInclude(f => f.Object)
.ToListAsync();
}

View File

@@ -314,9 +314,12 @@ public class BroadcastEventHandler(
await scopedDb.Files.Where(f => f.Id == fileId).ExecuteUpdateAsync(setter => setter
.SetProperty(f => f.UploadedAt, now)
.SetProperty(f => f.PoolId, destPool)
.SetProperty(f => f.MimeType, newMimeType)
.SetProperty(f => f.HasCompression, hasCompression)
.SetProperty(f => f.HasThumbnail, hasThumbnail)
);
await scopedDb.FileObjects.Where(fo => fo.Id == fileId).ExecuteUpdateAsync(setter => setter
.SetProperty(fo => fo.MimeType, newMimeType)
.SetProperty(fo => fo.HasCompression, hasCompression)
.SetProperty(fo => fo.HasThumbnail, hasThumbnail)
);
// Only delete temp file after successful upload and db update

View File

@@ -303,6 +303,7 @@ public class FileController(
.Where(e => e.IsMarkedRecycle == recycled)
.Where(e => e.AccountId == accountId)
.Include(e => e.Pool)
.Include(e => e.Object)
.AsQueryable();
if (pool.HasValue) filesQuery = filesQuery.Where(e => e.PoolId == pool);

View File

@@ -64,7 +64,10 @@ public class FileUploadController(
var accountId = Guid.Parse(currentUser.Id);
// Check if a file with the same hash already exists
var existingFile = await db.Files.FirstOrDefaultAsync(f => f.Hash == request.Hash);
var existingFile = await db.Files
.Include(f => f.Object)
.Where(f => f.Object != null && f.Object.Hash == request.Hash)
.FirstOrDefaultAsync();
if (existingFile != null)
{
// Create the file index if a path is provided, even for existing files

View File

@@ -20,14 +20,14 @@ public class SnCloudFile : ModelBase, ICloudFile, IIdentifiedResource
[NotMapped]
[Column(TypeName = "jsonb")]
public Dictionary<string, object?> FileMeta => Object!.Meta ?? [];
[NotMapped] [MaxLength(256)] public string? MimeType => Object!.MimeType;
[NotMapped] [MaxLength(256)] public string? Hash => Object!.Hash;
public Dictionary<string, object?> FileMeta => Object?.Meta ?? [];
[NotMapped] [MaxLength(256)] public string? MimeType => Object?.MimeType;
[NotMapped] [MaxLength(256)] public string? Hash => Object?.Hash;
public Instant? ExpiredAt { get; set; }
[NotMapped] public long Size => Object!.Size;
[NotMapped] public long Size => Object?.Size ?? 0;
public Instant? UploadedAt { get; set; }
[NotMapped] public bool HasCompression => Object!.HasCompression;
[NotMapped] public bool HasThumbnail => Object!.HasThumbnail;
[NotMapped] public bool HasCompression => Object?.HasCompression ?? false;
[NotMapped] public bool HasThumbnail => Object?.HasThumbnail ?? false;
[MaxLength(32)] public string? ObjectId { get; set; }
public SnFileObject? Object { get; set; }

View File

@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace DysonNetwork.Shared.Models;
@@ -33,7 +34,7 @@ public class SnFileReplica : ModelBase
public Guid Id { get; set; }
[MaxLength(32)] public string ObjectId { get; set; }
public SnFileObject Object { get; set; } = null!;
[JsonIgnore] public SnFileObject Object { get; set; } = null!;
public Guid? PoolId { get; set; }
public FilePool? Pool { get; set; } = null!;

View File

@@ -145,6 +145,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APutObjectArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F6efe388c7585d5dd5587416a55298550b030c2a107edf45f988791297c3ffa_003FPutObjectArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AQueryable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F42d8f09d6a294d00a6f49efc989927492fe00_003F4e_003F26d1ee34_003FQueryable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AQueryable_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcbafb95b4df34952928f87356db00c8f2fe00_003F9b_003F8ba036bb_003FQueryable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AQueryCompilationContext_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbb7b06734dde412ab7a17876ecec5dc22b0e20_003F5c_003Fa9a8ee00_003FQueryCompilationContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARazorPage_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F81d2924a2bbd4b0c864a1d23cbf5f0893d200_003F5f_003Fc110be1c_003FRazorPage_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARepeatedField_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F331aca3f6f414013b09964063341351379060_003Fc1_003F67c16263_003FRepeatedField_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARequestTimeoutPolicy_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb162d8ea71a447288973b864f5e7dea24ec00_003F46_003Ff75653ca_003FRequestTimeoutPolicy_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>