初始化
Some checks failed
Some checks failed
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using HardwarePerformance.Application.Interfaces;
|
||||
using HardwarePerformance.Core.Entities;
|
||||
using HardwarePerformance.Infrastructure.Data;
|
||||
|
||||
namespace HardwarePerformance.Infrastructure.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 类别Repository实现
|
||||
/// </summary>
|
||||
public class CategoryRepository : Repository<Category>, ICategoryRepository
|
||||
{
|
||||
public CategoryRepository(AppDbContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<Category?> GetByNameAsync(string name)
|
||||
{
|
||||
return await _dbSet
|
||||
.FirstOrDefaultAsync(c => c.Name == name);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Category>> GetCategoriesWithProductCountAsync()
|
||||
{
|
||||
return await _dbSet
|
||||
.Include(c => c.Products)
|
||||
.Select(c => new Category
|
||||
{
|
||||
Id = c.Id,
|
||||
Name = c.Name,
|
||||
Description = c.Description,
|
||||
IconUrl = c.IconUrl,
|
||||
Products = new List<Product>() // 不加载实际产品,只用于计数
|
||||
})
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> IsNameExistsAsync(string name, int? excludeId = null)
|
||||
{
|
||||
var query = _dbSet.Where(c => c.Name == name);
|
||||
|
||||
if (excludeId.HasValue)
|
||||
{
|
||||
query = query.Where(c => c.Id != excludeId.Value);
|
||||
}
|
||||
|
||||
return await query.AnyAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using HardwarePerformance.Application.Interfaces;
|
||||
using HardwarePerformance.Core.Entities;
|
||||
using HardwarePerformance.Infrastructure.Data;
|
||||
|
||||
namespace HardwarePerformance.Infrastructure.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 产品Repository实现
|
||||
/// </summary>
|
||||
public class ProductRepository : Repository<Product>, IProductRepository
|
||||
{
|
||||
public ProductRepository(AppDbContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<(IEnumerable<Product> products, int totalCount)> GetByCategoryAsync(
|
||||
int categoryId,
|
||||
int pageNumber = 1,
|
||||
int pageSize = 20,
|
||||
string sortBy = "CurrentRank",
|
||||
bool ascending = true)
|
||||
{
|
||||
var query = _dbSet
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.PerformanceScores)
|
||||
.Where(p => p.CategoryId == categoryId);
|
||||
|
||||
// 排序
|
||||
query = ApplySorting(query, sortBy, ascending);
|
||||
|
||||
var totalCount = await query.CountAsync();
|
||||
|
||||
var products = await query
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
return (products, totalCount);
|
||||
}
|
||||
|
||||
public async Task<Product?> GetByModelAsync(string model)
|
||||
{
|
||||
return await _dbSet
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.PerformanceScores)
|
||||
.FirstOrDefaultAsync(p => p.Model == model);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Product>> GetTopNByCategoryAsync(int categoryId, int n)
|
||||
{
|
||||
return await _dbSet
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.PerformanceScores)
|
||||
.Where(p => p.CategoryId == categoryId)
|
||||
.OrderBy(p => p.CurrentRank)
|
||||
.Take(n)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<(IEnumerable<Product> products, int totalCount)> SearchAsync(
|
||||
string searchTerm,
|
||||
int? categoryId = null,
|
||||
int pageNumber = 1,
|
||||
int pageSize = 20)
|
||||
{
|
||||
var query = _dbSet
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.PerformanceScores)
|
||||
.Where(p =>
|
||||
(string.IsNullOrEmpty(searchTerm) ||
|
||||
p.Name.Contains(searchTerm) ||
|
||||
p.Model.Contains(searchTerm) ||
|
||||
p.Manufacturer.Contains(searchTerm)) &&
|
||||
(!categoryId.HasValue || p.CategoryId == categoryId.Value));
|
||||
|
||||
var totalCount = await query.CountAsync();
|
||||
|
||||
var products = await query
|
||||
.OrderBy(p => p.CurrentRank)
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
return (products, totalCount);
|
||||
}
|
||||
|
||||
public async Task<(IEnumerable<Product> products, int totalCount)> FilterAsync(
|
||||
int categoryId,
|
||||
int? minScore = null,
|
||||
int? maxScore = null,
|
||||
int? minYear = null,
|
||||
int? maxYear = null,
|
||||
string? manufacturer = null,
|
||||
int pageNumber = 1,
|
||||
int pageSize = 20)
|
||||
{
|
||||
var query = _dbSet
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.PerformanceScores)
|
||||
.Where(p => p.CategoryId == categoryId);
|
||||
|
||||
// 性能分数筛选
|
||||
if (minScore.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.PerformanceScores.Any(ps => ps.Score >= minScore.Value));
|
||||
}
|
||||
|
||||
if (maxScore.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.PerformanceScores.Any(ps => ps.Score <= maxScore.Value));
|
||||
}
|
||||
|
||||
// 发布年份筛选
|
||||
if (minYear.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.ReleaseDate.HasValue && p.ReleaseDate.Value.Year >= minYear.Value);
|
||||
}
|
||||
|
||||
if (maxYear.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.ReleaseDate.HasValue && p.ReleaseDate.Value.Year <= maxYear.Value);
|
||||
}
|
||||
|
||||
// 品牌筛选
|
||||
if (!string.IsNullOrEmpty(manufacturer))
|
||||
{
|
||||
query = query.Where(p => p.Manufacturer == manufacturer);
|
||||
}
|
||||
|
||||
var totalCount = await query.CountAsync();
|
||||
|
||||
var products = await query
|
||||
.OrderBy(p => p.CurrentRank)
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
return (products, totalCount);
|
||||
}
|
||||
|
||||
public async Task<Product?> GetWithDetailsAsync(int id)
|
||||
{
|
||||
return await _dbSet
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.Specifications)
|
||||
.Include(p => p.PerformanceScores)
|
||||
.ThenInclude(ps => ps.DataSource)
|
||||
.Include(p => p.RankingHistories
|
||||
.OrderByDescending(rh => rh.RecordDate)
|
||||
.Take(12)) // 最近12个月的排名历史
|
||||
.FirstOrDefaultAsync(p => p.Id == id);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Product>> GetByIdsAsync(IEnumerable<int> productIds)
|
||||
{
|
||||
return await _dbSet
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.Specifications)
|
||||
.Include(p => p.PerformanceScores)
|
||||
.ThenInclude(ps => ps.DataSource)
|
||||
.Where(p => productIds.Contains(p.Id))
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> GetManufacturersAsync(int? categoryId = null)
|
||||
{
|
||||
var query = _dbSet.AsQueryable();
|
||||
|
||||
if (categoryId.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.CategoryId == categoryId.Value);
|
||||
}
|
||||
|
||||
return await query
|
||||
.Where(p => !string.IsNullOrEmpty(p.Manufacturer))
|
||||
.Select(p => p.Manufacturer)
|
||||
.Distinct()
|
||||
.OrderBy(m => m)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RankingHistory>> GetRankingHistoryAsync(int productId, int months = 12)
|
||||
{
|
||||
var startDate = DateTime.UtcNow.AddMonths(-months);
|
||||
|
||||
return await _context.RankingHistories
|
||||
.Where(rh => rh.ProductId == productId && rh.RecordDate >= startDate)
|
||||
.OrderBy(rh => rh.RecordDate)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<(IEnumerable<Product> products, int totalCount)> GetByManufacturerAsync(
|
||||
string manufacturer,
|
||||
int? categoryId = null,
|
||||
int pageNumber = 1,
|
||||
int pageSize = 20)
|
||||
{
|
||||
var query = _dbSet
|
||||
.Include(p => p.Category)
|
||||
.Include(p => p.PerformanceScores)
|
||||
.Where(p => p.Manufacturer == manufacturer);
|
||||
|
||||
if (categoryId.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.CategoryId == categoryId.Value);
|
||||
}
|
||||
|
||||
var totalCount = await query.CountAsync();
|
||||
|
||||
var products = await query
|
||||
.OrderBy(p => p.CurrentRank)
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
return (products, totalCount);
|
||||
}
|
||||
|
||||
private IQueryable<Product> ApplySorting(IQueryable<Product> query, string sortBy, bool ascending)
|
||||
{
|
||||
return sortBy.ToLower() switch
|
||||
{
|
||||
"name" => ascending ? query.OrderBy(p => p.Name) : query.OrderByDescending(p => p.Name),
|
||||
"manufacturer" => ascending ? query.OrderBy(p => p.Manufacturer) : query.OrderByDescending(p => p.Manufacturer),
|
||||
"releasedate" => ascending ? query.OrderBy(p => p.ReleaseDate) : query.OrderByDescending(p => p.ReleaseDate),
|
||||
"currentrank" => ascending ? query.OrderBy(p => p.CurrentRank) : query.OrderByDescending(p => p.CurrentRank),
|
||||
"score" => ascending ?
|
||||
query.OrderBy(p => p.PerformanceScores.Any() ? p.PerformanceScores.Average(ps => ps.Score) : 0) :
|
||||
query.OrderByDescending(p => p.PerformanceScores.Any() ? p.PerformanceScores.Average(ps => ps.Score) : 0),
|
||||
_ => ascending ? query.OrderBy(p => p.CurrentRank) : query.OrderByDescending(p => p.CurrentRank)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using HardwarePerformance.Application.Interfaces;
|
||||
using HardwarePerformance.Infrastructure.Data;
|
||||
|
||||
namespace HardwarePerformance.Infrastructure.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// 通用Repository基类,实现基本的CRUD操作
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体类型</typeparam>
|
||||
public class Repository<T> : IRepository<T> where T : class
|
||||
{
|
||||
protected readonly AppDbContext _context;
|
||||
protected readonly DbSet<T> _dbSet;
|
||||
|
||||
public Repository(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
_dbSet = context.Set<T>();
|
||||
}
|
||||
|
||||
public virtual async Task<T?> GetByIdAsync(int id)
|
||||
{
|
||||
return await _dbSet.FindAsync(id);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<T>> GetAllAsync()
|
||||
{
|
||||
return await _dbSet.ToListAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<T>> FindAsync(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
return await _dbSet.Where(predicate).ToListAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<bool> ExistsAsync(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
return await _dbSet.AnyAsync(predicate);
|
||||
}
|
||||
|
||||
public virtual async Task<T> AddAsync(T entity)
|
||||
{
|
||||
await _dbSet.AddAsync(entity);
|
||||
await _context.SaveChangesAsync();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<T>> AddRangeAsync(IEnumerable<T> entities)
|
||||
{
|
||||
await _dbSet.AddRangeAsync(entities);
|
||||
await _context.SaveChangesAsync();
|
||||
return entities;
|
||||
}
|
||||
|
||||
public virtual async Task<T> UpdateAsync(T entity)
|
||||
{
|
||||
_dbSet.Update(entity);
|
||||
await _context.SaveChangesAsync();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> DeleteAsync(T entity)
|
||||
{
|
||||
_dbSet.Remove(entity);
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> DeleteByIdAsync(int id)
|
||||
{
|
||||
var entity = await GetByIdAsync(id);
|
||||
if (entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return await DeleteAsync(entity);
|
||||
}
|
||||
|
||||
public virtual async Task<int> CountAsync()
|
||||
{
|
||||
return await _dbSet.CountAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<int> CountAsync(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
return await _dbSet.CountAsync(predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user