AssetManager.API/AssetManager.Data/Repositories/PortfolioRepository.cs
OpenClaw Agent 4ce29a1036 refactor: 架构优化 P0-P3
P0 - 安全修复:
- 移除硬编码 API Key,启动时校验必填环境变量

P1 - 高优先级:
- Entity 拆分:Position.cs, Transaction.cs 独立文件
- Controller Facade 封装:IPortfolioFacade 减少依赖注入

P2 - 中优先级:
- Repository 抽象:IPortfolioRepository, IMarketDataRepository
- MarketDataService 拆分:组合模式整合 Tencent/Tiingo/OKX

P3 - 低优先级:
- DTO 命名规范:统一 PascalCase
- 单元测试框架:xUnit + Moq + FluentAssertions
2026-03-15 12:54:05 +00:00

159 lines
4.9 KiB
C#

using AssetManager.Data;
using Microsoft.Extensions.Logging;
using SqlSugar;
namespace AssetManager.Data.Repositories;
/// <summary>
/// 投资组合仓储实现
/// </summary>
public class PortfolioRepository : IPortfolioRepository
{
private readonly ISqlSugarClient _db;
private readonly ILogger<PortfolioRepository> _logger;
public PortfolioRepository(ISqlSugarClient db, ILogger<PortfolioRepository> logger)
{
_db = db;
_logger = logger;
}
// ===== Portfolio =====
public async Task<Portfolio?> GetByIdAsync(string id, string userId)
{
return await _db.Queryable<Portfolio>()
.Where(p => p.Id == id && p.UserId == userId)
.FirstAsync();
}
public async Task<List<Portfolio>> GetByUserIdAsync(string userId)
{
return await _db.Queryable<Portfolio>()
.Where(p => p.UserId == userId)
.ToListAsync();
}
public async Task<Portfolio> CreateAsync(Portfolio portfolio)
{
await _db.Insertable(portfolio).ExecuteCommandAsync();
return portfolio;
}
public async Task<bool> UpdateAsync(Portfolio portfolio)
{
portfolio.UpdatedAt = DateTime.Now;
return await _db.Updateable(portfolio).ExecuteCommandAsync() > 0;
}
public async Task<bool> DeleteAsync(string id, string userId)
{
var portfolio = await GetByIdAsync(id, userId);
if (portfolio == null) return false;
// 删除相关数据
await _db.Deleteable<Position>().Where(p => p.PortfolioId == id).ExecuteCommandAsync();
await _db.Deleteable<Transaction>().Where(t => t.PortfolioId == id).ExecuteCommandAsync();
await _db.Deleteable<PortfolioNavHistory>().Where(n => n.PortfolioId == id).ExecuteCommandAsync();
return await _db.Deleteable(portfolio).ExecuteCommandAsync() > 0;
}
// ===== Position =====
public async Task<List<Position>> GetPositionsByPortfolioIdAsync(string portfolioId)
{
return await _db.Queryable<Position>()
.Where(p => p.PortfolioId == portfolioId)
.ToListAsync();
}
public async Task<Position?> GetPositionAsync(string portfolioId, string stockCode)
{
return await _db.Queryable<Position>()
.Where(p => p.PortfolioId == portfolioId && p.StockCode == stockCode)
.FirstAsync();
}
public async Task<Position> CreatePositionAsync(Position position)
{
position.CreatedAt = DateTime.Now;
position.UpdatedAt = DateTime.Now;
await _db.Insertable(position).ExecuteCommandAsync();
return position;
}
public async Task<bool> UpdatePositionAsync(Position position)
{
position.UpdatedAt = DateTime.Now;
return await _db.Updateable(position).ExecuteCommandAsync() > 0;
}
public async Task<bool> DeletePositionAsync(string positionId)
{
return await _db.Deleteable<Position>()
.Where(p => p.Id == positionId)
.ExecuteCommandAsync() > 0;
}
// ===== Transaction =====
public async Task<List<Transaction>> GetTransactionsAsync(string portfolioId, int limit, int offset)
{
return await _db.Queryable<Transaction>()
.Where(t => t.PortfolioId == portfolioId)
.OrderByDescending(t => t.TransactionTime)
.Skip(offset)
.Take(limit)
.ToListAsync();
}
public async Task<int> GetTransactionCountAsync(string portfolioId)
{
return await _db.Queryable<Transaction>()
.Where(t => t.PortfolioId == portfolioId)
.CountAsync();
}
public async Task<Transaction> CreateTransactionAsync(Transaction transaction)
{
transaction.CreatedAt = DateTime.Now;
await _db.Insertable(transaction).ExecuteCommandAsync();
return transaction;
}
// ===== NavHistory =====
public async Task<List<PortfolioNavHistory>> GetNavHistoryAsync(string portfolioId, DateTime? startDate, DateTime? endDate)
{
var query = _db.Queryable<PortfolioNavHistory>()
.Where(n => n.PortfolioId == portfolioId);
if (startDate.HasValue)
{
query = query.Where(n => n.Date >= startDate.Value.Date);
}
if (endDate.HasValue)
{
query = query.Where(n => n.Date <= endDate.Value.Date);
}
return await query.OrderBy(n => n.Date).ToListAsync();
}
public async Task<int> DeleteNavHistoryAfterDateAsync(string portfolioId, DateTime date)
{
return await _db.Deleteable<PortfolioNavHistory>()
.Where(n => n.PortfolioId == portfolioId && n.Date >= date.Date)
.ExecuteCommandAsync();
}
public async Task<int> CreateNavHistoryBatchAsync(List<PortfolioNavHistory> records)
{
if (records == null || records.Count == 0) return 0;
return await _db.Insertable(records)
.ExecuteCommandAsync();
}
}