using Microsoft.EntityFrameworkCore; using Sharp.Data; using Sharp.Data.Context; namespace Data.Test; /// /// 演示 02: 仓储 CRUD 操作 /// /// 本测试类演示: /// 1. 添加数据 (Create) /// 2. 查询数据 (Read) /// 3. 更新数据 (Update) /// 4. 删除数据 (Delete) /// 5. 批量操作 /// 6. 条件查询 /// [TestClass] public class _02_RepositoryCRUDTests { private IDataContext _db = null!; [TestInitialize] public void Setup() { var builder = new DataContextBuilder(); builder.UseInMemoryDatabase($"CRUDDemo_{Guid.NewGuid()}"); _db = builder.Build(); } [TestCleanup] public void Cleanup() { _db?.Dispose(); } #region Create - 添加数据 /// /// 演示: 添加单个实体 /// [TestMethod] public async Task Demo_AddSingleEntity() { var repo = _db.Repository(); // 创建新产品 var product = new Product { Name = "iPhone 15", Price = 7999.00m, Description = "最新款 iPhone", Stock = 100 }; // 添加到数据库 await repo.AddAsync(product); await _db.SaveChangesAsync(); Console.WriteLine("✓ 成功添加产品"); Console.WriteLine($" - ID: {product.Id}"); Console.WriteLine($" - 名称: {product.Name}"); Console.WriteLine($" - 价格: {product.Price:C}"); // 验证 var savedProduct = await repo.GetByIdAsync(product.Id); Assert.IsNotNull(savedProduct); Assert.AreEqual("iPhone 15", savedProduct.Name); } /// /// 演示: 批量添加实体 /// [TestMethod] public async Task Demo_AddMultipleEntities() { var repo = _db.Repository(); // 创建多个产品 var products = new List { new() { Name = "MacBook Pro", Price = 12999.00m, Stock = 50 }, new() { Name = "iPad Air", Price = 4799.00m, Stock = 80 }, new() { Name = "AirPods Pro", Price = 1899.00m, Stock = 200 } }; // 批量添加 await repo.AddRangeAsync(products); await _db.SaveChangesAsync(); Console.WriteLine($"✓ 成功添加 {products.Count} 个产品"); foreach (var product in products) Console.WriteLine($" - {product.Name}: {product.Price:C}"); // 验证 var allProducts = await repo.GetAllAsync(); Assert.AreEqual(3, allProducts.Count); } #endregion #region Read - 查询数据 /// /// 演示: 根据 ID 获取实体 /// [TestMethod] public async Task Demo_GetById() { var repo = _db.Repository(); // 先添加数据 var product = new Product { Name = "测试产品", Price = 99.00m, Stock = 10 }; await repo.AddAsync(product); await _db.SaveChangesAsync(); // 根据 ID 查询 var found = await repo.GetByIdAsync(product.Id); Assert.IsNotNull(found); Assert.AreEqual(product.Id, found.Id); Console.WriteLine($"✓ 通过 ID 查询成功: {found.Name}"); } /// /// 演示: 获取所有数据 /// [TestMethod] public async Task Demo_GetAll() { var repo = _db.Repository(); // 添加测试数据 await repo.AddRangeAsync(new[] { new Product { Name = "产品1", Price = 100m, Stock = 10 }, new Product { Name = "产品2", Price = 200m, Stock = 20 }, new Product { Name = "产品3", Price = 300m, Stock = 30 } }); await _db.SaveChangesAsync(); // 获取所有数据 var allProducts = await repo.GetAllAsync(); Assert.AreEqual(3, allProducts.Count); Console.WriteLine($"✓ 获取所有数据成功,共 {allProducts.Count} 条"); foreach (var p in allProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}"); } /// /// 演示: 条件查询 /// [TestMethod] public async Task Demo_FindWithCondition() { var repo = _db.Repository(); // 添加测试数据 await repo.AddRangeAsync(new[] { new Product { Name = "苹果手机", Price = 7999m, Stock = 50 }, new Product { Name = "苹果平板", Price = 4799m, Stock = 30 }, new Product { Name = "华为手机", Price = 6999m, Stock = 40 } }); await _db.SaveChangesAsync(); // 查找名称包含"苹果"的产品 var appleProducts = await repo.FindAsync(p => p.Name.Contains("苹果")); Assert.AreEqual(2, appleProducts.Count); Console.WriteLine("✓ 条件查询成功,找到包含'苹果'的产品:"); foreach (var p in appleProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}"); } /// /// 演示: 获取第一个符合条件的实体 /// [TestMethod] public async Task Demo_FirstOrDefault() { var repo = _db.Repository(); // 添加测试数据 await repo.AddRangeAsync(new[] { new Product { Name = "产品A", Price = 100m, Stock = 10 }, new Product { Name = "产品B", Price = 200m, Stock = 20 } }); await _db.SaveChangesAsync(); // 查找第一个价格大于150的产品 var expensiveProduct = await repo.FirstOrDefaultAsync(p => p.Price > 150); Assert.IsNotNull(expensiveProduct); Assert.AreEqual("产品B", expensiveProduct.Name); Console.WriteLine($"✓ 找到第一个价格>150的产品: {expensiveProduct.Name}"); // 查找不存在的条件 var notFound = await repo.FirstOrDefaultAsync(p => p.Price > 1000); Assert.IsNull(notFound); Console.WriteLine("✓ 不存在的条件返回 null"); } /// /// 演示: 统计查询 /// [TestMethod] public async Task Demo_CountAndAny() { var repo = _db.Repository(); // 添加测试数据 await repo.AddRangeAsync(new[] { new Product { Name = "产品1", Price = 100m, Stock = 10 }, new Product { Name = "产品2", Price = 200m, Stock = 20 }, new Product { Name = "产品3", Price = 300m, Stock = 30 } }); await _db.SaveChangesAsync(); // 统计总数 var totalCount = await repo.CountAsync(); Console.WriteLine($"✓ 总记录数: {totalCount}"); Assert.AreEqual(3, totalCount); // 统计符合条件的数量 var expensiveCount = await repo.CountAsync(p => p.Price > 150); Console.WriteLine($"✓ 价格>150的产品数: {expensiveCount}"); Assert.AreEqual(2, expensiveCount); // 检查是否存在 var hasExpensive = await repo.AnyAsync(p => p.Price > 250); Console.WriteLine($"✓ 是否存在价格>250的产品: {hasExpensive}"); Assert.IsTrue(hasExpensive); var hasVeryExpensive = await repo.AnyAsync(p => p.Price > 500); Console.WriteLine($"✓ 是否存在价格>500的产品: {hasVeryExpensive}"); Assert.IsFalse(hasVeryExpensive); } /// /// 演示: 使用 Query 方法进行复杂查询 /// [TestMethod] public async Task Demo_ComplexQueryWithLinq() { var repo = _db.Repository(); // 添加测试数据 await repo.AddRangeAsync(new[] { new Product { Name = "iPhone", Price = 7999m, Stock = 50 }, new Product { Name = "iPad", Price = 4799m, Stock = 30 }, new Product { Name = "MacBook", Price = 12999m, Stock = 20 }, new Product { Name = "AirPods", Price = 1899m, Stock = 100 } }); await _db.SaveChangesAsync(); // 获取可查询对象,进行复杂查询 var query = repo.Query(false); // trackChanges: false 提升查询性能 var result = await query .Where(p => p.Price > 2000) // 价格大于2000 .OrderByDescending(p => p.Price) // 按价格降序 .Select(p => new // 投影到匿名类型 { p.Name, p.Price, p.Stock, TotalValue = p.Price * p.Stock // 计算总价值 }) .ToListAsync(); Console.WriteLine("✓ 复杂查询成功,价格>2000的产品(按价格降序):"); foreach (var item in result) Console.WriteLine($" - {item.Name}: {item.Price:C} x {item.Stock} = {item.TotalValue:C}"); Assert.AreEqual(3, result.Count); } #endregion #region Update - 更新数据 /// /// 演示: 更新实体 /// [TestMethod] public async Task Demo_UpdateEntity() { var repo = _db.Repository(); // 添加产品 var product = new Product { Name = "旧名称", Price = 100m, Stock = 50 }; await repo.AddAsync(product); await _db.SaveChangesAsync(); Console.WriteLine($"✓ 原始数据: {product.Name}, 价格: {product.Price:C}"); // 修改产品 product.Name = "新名称"; product.Price = 200m; repo.Update(product); await _db.SaveChangesAsync(); Console.WriteLine($"✓ 更新后: {product.Name}, 价格: {product.Price:C}"); // 验证更新 var updated = await repo.GetByIdAsync(product.Id); Assert.AreEqual("新名称", updated!.Name); Assert.AreEqual(200m, updated.Price); } /// /// 演示: 批量更新 /// [TestMethod] public async Task Demo_UpdateMultipleEntities() { var repo = _db.Repository(); // 添加产品 var products = new List { new() { Name = "产品1", Price = 100m, Stock = 10 }, new() { Name = "产品2", Price = 200m, Stock = 20 }, new() { Name = "产品3", Price = 300m, Stock = 30 } }; await repo.AddRangeAsync(products); await _db.SaveChangesAsync(); // 批量涨价 10% foreach (var product in products) product.Price *= 1.10m; repo.UpdateRange(products); await _db.SaveChangesAsync(); Console.WriteLine("✓ 批量涨价 10% 成功:"); var updatedProducts = await repo.GetAllAsync(); foreach (var p in updatedProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}"); // 验证 Assert.AreEqual(110m, updatedProducts[0].Price); } #endregion #region Delete - 删除数据 /// /// 演示: 删除实体 (物理删除) /// /// 注意: 对于实现了 ISoftDeletable 的实体,RemoveAsync 会变成软删除 /// 本例中的 Product 继承自 AuditableEntity,实现了软删除接口 /// 所以这个测试实际演示的是软删除,详见 04_SoftDeleteTests /// [TestMethod] public async Task Demo_DeleteEntity() { var repo = _db.Repository(); // Category 没有软删除,是真实删除 // 添加分类 var category = new Category { Name = "测试分类" }; await repo.AddAsync(category); await _db.SaveChangesAsync(); Console.WriteLine($"✓ 添加分类: {category.Name}, ID: {category.Id}"); // 删除分类 repo.Remove(category); await _db.SaveChangesAsync(); Console.WriteLine("✓ 删除分类成功"); // 验证删除 var deleted = await repo.GetByIdAsync(category.Id); Assert.IsNull(deleted); Console.WriteLine("✓ 验证: 分类已被物理删除"); } /// /// 演示: 根据 ID 删除 /// [TestMethod] public async Task Demo_DeleteById() { var repo = _db.Repository(); // 添加分类 var category = new Category { Name = "要删除的分类" }; await repo.AddAsync(category); await _db.SaveChangesAsync(); var categoryId = category.Id; Console.WriteLine($"✓ 添加分类: ID={categoryId}"); // 根据 ID 删除 await repo.RemoveAsync(categoryId); await _db.SaveChangesAsync(); Console.WriteLine("✓ 根据 ID 删除成功"); // 验证删除 var deleted = await repo.GetByIdAsync(categoryId); Assert.IsNull(deleted); } /// /// 演示: 批量删除 /// [TestMethod] public async Task Demo_DeleteMultipleEntities() { var repo = _db.Repository(); // 添加多个分类 var categories = new List { new() { Name = "分类1" }, new() { Name = "分类2" }, new() { Name = "分类3" } }; await repo.AddRangeAsync(categories); await _db.SaveChangesAsync(); Console.WriteLine($"✓ 添加了 {categories.Count} 个分类"); // 批量删除 repo.RemoveRange(categories); await _db.SaveChangesAsync(); Console.WriteLine("✓ 批量删除成功"); // 验证 var remaining = await repo.GetAllAsync(); Assert.AreEqual(0, remaining.Count); } #endregion #region 高级查询 /// /// 演示: 排序查询 /// [TestMethod] public async Task Demo_OrderedQuery() { var repo = _db.Repository(); // 添加测试数据 await repo.AddRangeAsync(new[] { new Product { Name = "C产品", Price = 300m, Stock = 30 }, new Product { Name = "A产品", Price = 100m, Stock = 10 }, new Product { Name = "B产品", Price = 200m, Stock = 20 } }); await _db.SaveChangesAsync(); // 按价格升序 var ascProducts = await repo.Query() .OrderBy(p => p.Price) .ToListAsync(); Console.WriteLine("✓ 按价格升序:"); foreach (var p in ascProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}"); // 按价格降序 var descProducts = await repo.Query() .OrderByDescending(p => p.Price) .ToListAsync(); Console.WriteLine("✓ 按价格降序:"); foreach (var p in descProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}"); Assert.AreEqual("A产品", ascProducts[0].Name); Assert.AreEqual("C产品", descProducts[0].Name); } /// /// 演示: 分组查询 /// [TestMethod] public async Task Demo_GroupQuery() { var repo = _db.Repository(); // 添加不同价格区间的产品 await repo.AddRangeAsync(new[] { new Product { Name = "低价产品1", Price = 50m, Stock = 10 }, new Product { Name = "低价产品2", Price = 80m, Stock = 20 }, new Product { Name = "中价产品1", Price = 150m, Stock = 15 }, new Product { Name = "中价产品2", Price = 180m, Stock = 25 }, new Product { Name = "高价产品1", Price = 500m, Stock = 5 }, new Product { Name = "高价产品2", Price = 600m, Stock = 8 } }); await _db.SaveChangesAsync(); // 按价格区间分组统计 var priceGroups = await repo.Query() .GroupBy(p => p.Price < 100 ? "低价" : p.Price < 300 ? "中价" : "高价") .Select(g => new { PriceRange = g.Key, Count = g.Count(), AvgPrice = g.Average(p => p.Price), TotalStock = g.Sum(p => p.Stock) }) .ToListAsync(); Console.WriteLine("✓ 按价格区间分组统计:"); foreach (var group in priceGroups) Console.WriteLine( $" - {group.PriceRange}: {group.Count}个产品, 平均价格 {group.AvgPrice:C}, 总库存 {group.TotalStock}"); Assert.AreEqual(3, priceGroups.Count); } #endregion }