A:增加数据库配置和使用
This commit is contained in:
1 parent
53d1dd2dbf
commit
f7660c49e8
86 files changed
+7401
-271
No files matched your search
@@ -0,0 +1,548 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Sharp.Data;
|
||||
using Sharp.Data.Context;
|
||||
|
||||
namespace Data.Test;
|
||||
|
||||
/// <summary>
|
||||
/// 演示 02: 仓储 CRUD 操作
|
||||
///
|
||||
/// 本测试类演示:
|
||||
/// 1. 添加数据 (Create)
|
||||
/// 2. 查询数据 (Read)
|
||||
/// 3. 更新数据 (Update)
|
||||
/// 4. 删除数据 (Delete)
|
||||
/// 5. 批量操作
|
||||
/// 6. 条件查询
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public class _02_RepositoryCRUDTests
|
||||
{
|
||||
private IDataContext _db = null!;
|
||||
|
||||
[TestInitialize]
|
||||
public void Setup()
|
||||
{
|
||||
var builder = new DataContextBuilder<TestDbContext>();
|
||||
builder.UseInMemoryDatabase($"CRUDDemo_{Guid.NewGuid()}");
|
||||
_db = builder.Build();
|
||||
}
|
||||
|
||||
[TestCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
_db?.Dispose();
|
||||
}
|
||||
|
||||
#region Create - 添加数据
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 添加单个实体
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_AddSingleEntity()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 创建新产品
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 批量添加实体
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_AddMultipleEntities()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 创建多个产品
|
||||
var products = new List<Product>
|
||||
{
|
||||
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 - 查询数据
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 根据 ID 获取实体
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_GetById()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 先添加数据
|
||||
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}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 获取所有数据
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_GetAll()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 条件查询
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_FindWithCondition()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 获取第一个符合条件的实体
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_FirstOrDefault()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
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");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 统计查询
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_CountAndAny()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 使用 Query 方法进行复杂查询
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_ComplexQueryWithLinq()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
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(trackChanges: 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 - 更新数据
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 更新实体
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_UpdateEntity()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加产品
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 批量更新
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_UpdateMultipleEntities()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加产品
|
||||
var products = new List<Product>
|
||||
{
|
||||
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 - 删除数据
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 删除实体 (物理删除)
|
||||
///
|
||||
/// 注意: 对于实现了 ISoftDeletable 的实体,RemoveAsync 会变成软删除
|
||||
/// 本例中的 Product 继承自 AuditableEntity,实现了软删除接口
|
||||
/// 所以这个测试实际演示的是软删除,详见 04_SoftDeleteTests
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_DeleteEntity()
|
||||
{
|
||||
var repo = _db.Repository<Category>(); // 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("✓ 验证: 分类已被物理删除");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 根据 ID 删除
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_DeleteById()
|
||||
{
|
||||
var repo = _db.Repository<Category>();
|
||||
|
||||
// 添加分类
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 批量删除
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_DeleteMultipleEntities()
|
||||
{
|
||||
var repo = _db.Repository<Category>();
|
||||
|
||||
// 添加多个分类
|
||||
var categories = new List<Category>
|
||||
{
|
||||
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 高级查询
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 排序查询
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_OrderedQuery()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 演示: 分组查询
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public async Task Demo_GroupQuery()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 添加不同价格区间的产品
|
||||
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
|
||||
}
|
||||
Reference in new issue
Block a user