106 lines
3.7 KiB
C#
106 lines
3.7 KiB
C#
using DramaLing.Api.Data;
|
|
using DramaLing.Api.Models.Entities;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System.Text.Json;
|
|
|
|
namespace DramaLing.Api.Services.Infrastructure.Caching;
|
|
|
|
public class DatabaseCacheManager : IDatabaseCacheManager
|
|
{
|
|
private readonly DramaLingDbContext _dbContext;
|
|
private readonly ICacheSerializer _serializer;
|
|
private readonly ILogger<DatabaseCacheManager> _logger;
|
|
|
|
public DatabaseCacheManager(
|
|
DramaLingDbContext dbContext,
|
|
ICacheSerializer serializer,
|
|
ILogger<DatabaseCacheManager> logger)
|
|
{
|
|
_dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
|
|
_serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
public async Task<T?> GetFromDatabaseCacheAsync<T>(string key) where T : class
|
|
{
|
|
try
|
|
{
|
|
if (!key.StartsWith("analysis:")) return null;
|
|
|
|
var hash = key.Replace("analysis:", "");
|
|
var cached = await _dbContext.SentenceAnalysisCache
|
|
.AsNoTracking()
|
|
.FirstOrDefaultAsync(c => c.InputTextHash == hash && c.ExpiresAt > DateTime.UtcNow);
|
|
|
|
if (cached != null)
|
|
{
|
|
// 更新訪問統計
|
|
cached.AccessCount++;
|
|
cached.LastAccessedAt = DateTime.UtcNow;
|
|
await _dbContext.SaveChangesAsync();
|
|
|
|
var jsonBytes = System.Text.Encoding.UTF8.GetBytes(cached.AnalysisResult);
|
|
var result = _serializer.Deserialize<T>(jsonBytes);
|
|
|
|
_logger.LogDebug("Database cache hit for key: {Key}", key);
|
|
return result;
|
|
}
|
|
|
|
_logger.LogDebug("Database cache miss for key: {Key}", key);
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting from database cache for key: {Key}", key);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async Task SaveToDatabaseCacheAsync<T>(string key, T value, TimeSpan expiry) where T : class
|
|
{
|
|
try
|
|
{
|
|
if (!key.StartsWith("analysis:")) return;
|
|
|
|
var hash = key.Replace("analysis:", "");
|
|
var expiresAt = DateTime.UtcNow.Add(expiry);
|
|
|
|
var existing = await _dbContext.SentenceAnalysisCache
|
|
.FirstOrDefaultAsync(c => c.InputTextHash == hash);
|
|
|
|
var jsonBytes = _serializer.Serialize(value);
|
|
var jsonString = System.Text.Encoding.UTF8.GetString(jsonBytes);
|
|
|
|
if (existing != null)
|
|
{
|
|
existing.AnalysisResult = jsonString;
|
|
existing.ExpiresAt = expiresAt;
|
|
existing.AccessCount++;
|
|
existing.LastAccessedAt = DateTime.UtcNow;
|
|
}
|
|
else
|
|
{
|
|
var cacheItem = new SentenceAnalysisCache
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
InputTextHash = hash,
|
|
InputText = "",
|
|
AnalysisResult = jsonString,
|
|
CreatedAt = DateTime.UtcNow,
|
|
ExpiresAt = expiresAt,
|
|
AccessCount = 1,
|
|
LastAccessedAt = DateTime.UtcNow
|
|
};
|
|
|
|
_dbContext.SentenceAnalysisCache.Add(cacheItem);
|
|
}
|
|
|
|
await _dbContext.SaveChangesAsync();
|
|
_logger.LogDebug("Database cache saved for key: {Key}", key);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error saving to database cache for key: {Key}", key);
|
|
}
|
|
}
|
|
} |