U:调整所有代码格式
This commit is contained in:
1 parent
d133bacf55
commit
155b67e831
342 files changed
+9431
-9868
No files matched your search
@@ -53,9 +53,9 @@ public class _00_QuickStart
|
||||
{
|
||||
var builder = new DataContextBuilder<TestDbContext>();
|
||||
builder.UseInMemoryDatabase($"AuditDemo_{Guid.NewGuid()}")
|
||||
.UseAudit(true) // 启用审计
|
||||
.UseSoftDelete(true) // 启用软删除
|
||||
.UseCurrentUser("admin"); // 设置当前用户
|
||||
.UseAudit(true) // 启用审计
|
||||
.UseSoftDelete(true) // 启用软删除
|
||||
.UseCurrentUser("admin"); // 设置当前用户
|
||||
|
||||
using var db = builder.Build();
|
||||
var repo = db.Repository<Product>();
|
||||
@@ -96,15 +96,13 @@ public class _00_QuickStart
|
||||
var repo = db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
for (int i = 1; i <= 25; i++)
|
||||
{
|
||||
for (var i = 1; i <= 25; i++)
|
||||
await repo.AddAsync(new Product
|
||||
{
|
||||
Name = $"产品{i}",
|
||||
Price = i * 10m,
|
||||
Stock = i
|
||||
});
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// 分页查询:第2页,每页10条
|
||||
@@ -181,4 +179,4 @@ public class _00_QuickStart
|
||||
Assert.AreEqual(1, count);
|
||||
Console.WriteLine($"✓ 可以直接使用 EF Core,完全兼容!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,12 +69,12 @@ public class _01_BasicUsageTests
|
||||
|
||||
// 链式配置所有功能
|
||||
builder.UseInMemoryDatabase("FullConfigDemo")
|
||||
.UseAudit(true) // 启用审计功能
|
||||
.UseSoftDelete(true) // 启用软删除功能
|
||||
.UseAutoMigration(true) // 启动时自动迁移数据库
|
||||
.UseCurrentUser("admin") // 设置当前用户(用于审计)
|
||||
.EnableDetailedErrors(true) // 启用详细错误信息
|
||||
.EnableSensitiveDataLogging(true); // 启用敏感数据日志(仅开发环境)
|
||||
.UseAudit(true) // 启用审计功能
|
||||
.UseSoftDelete(true) // 启用软删除功能
|
||||
.UseAutoMigration(true) // 启动时自动迁移数据库
|
||||
.UseCurrentUser("admin") // 设置当前用户(用于审计)
|
||||
.EnableDetailedErrors(true) // 启用详细错误信息
|
||||
.EnableSensitiveDataLogging(true); // 启用敏感数据日志(仅开发环境)
|
||||
|
||||
using var db = builder.Build();
|
||||
|
||||
@@ -126,8 +126,8 @@ public class _01_BasicUsageTests
|
||||
|
||||
// 只启用审计,不启用软删除
|
||||
builder.UseInMemoryDatabase("SelectiveDemo")
|
||||
.UseAudit(true) // 启用审计
|
||||
.UseSoftDelete(false); // 不启用软删除
|
||||
.UseAudit(true) // 启用审计
|
||||
.UseSoftDelete(false); // 不启用软删除
|
||||
|
||||
using var db = builder.Build();
|
||||
|
||||
@@ -269,4 +269,4 @@ public class _01_BasicUsageTests
|
||||
builder.UseInMemoryDatabase($"TestDb_{Guid.NewGuid()}");
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,10 +89,7 @@ public class _02_RepositoryCRUDTests
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
Console.WriteLine($"✓ 成功添加 {products.Count} 个产品");
|
||||
foreach (var product in products)
|
||||
{
|
||||
Console.WriteLine($" - {product.Name}: {product.Price:C}");
|
||||
}
|
||||
foreach (var product in products) Console.WriteLine($" - {product.Name}: {product.Price:C}");
|
||||
|
||||
// 验证
|
||||
var allProducts = await repo.GetAllAsync();
|
||||
@@ -146,10 +143,7 @@ public class _02_RepositoryCRUDTests
|
||||
|
||||
Assert.AreEqual(3, allProducts.Count);
|
||||
Console.WriteLine($"✓ 获取所有数据成功,共 {allProducts.Count} 条");
|
||||
foreach (var p in allProducts)
|
||||
{
|
||||
Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
}
|
||||
foreach (var p in allProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -174,10 +168,7 @@ public class _02_RepositoryCRUDTests
|
||||
|
||||
Assert.AreEqual(2, appleProducts.Count);
|
||||
Console.WriteLine("✓ 条件查询成功,找到包含'苹果'的产品:");
|
||||
foreach (var p in appleProducts)
|
||||
{
|
||||
Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
}
|
||||
foreach (var p in appleProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -265,25 +256,23 @@ public class _02_RepositoryCRUDTests
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// 获取可查询对象,进行复杂查询
|
||||
var query = repo.Query(trackChanges: false); // trackChanges: false 提升查询性能
|
||||
var query = repo.Query(false); // trackChanges: false 提升查询性能
|
||||
|
||||
var result = await query
|
||||
.Where(p => p.Price > 2000) // 价格大于2000
|
||||
.OrderByDescending(p => p.Price) // 按价格降序
|
||||
.Select(p => new // 投影到匿名类型
|
||||
.Where(p => p.Price > 2000) // 价格大于2000
|
||||
.OrderByDescending(p => p.Price) // 按价格降序
|
||||
.Select(p => new // 投影到匿名类型
|
||||
{
|
||||
p.Name,
|
||||
p.Price,
|
||||
p.Stock,
|
||||
TotalValue = 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);
|
||||
}
|
||||
@@ -345,19 +334,13 @@ public class _02_RepositoryCRUDTests
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
// 批量涨价 10%
|
||||
foreach (var product in products)
|
||||
{
|
||||
product.Price *= 1.10m;
|
||||
}
|
||||
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}");
|
||||
}
|
||||
foreach (var p in updatedProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
|
||||
// 验证
|
||||
Assert.AreEqual(110m, updatedProducts[0].Price);
|
||||
@@ -377,7 +360,7 @@ public class _02_RepositoryCRUDTests
|
||||
[TestMethod]
|
||||
public async Task Demo_DeleteEntity()
|
||||
{
|
||||
var repo = _db.Repository<Category>(); // Category 没有软删除,是真实删除
|
||||
var repo = _db.Repository<Category>(); // Category 没有软删除,是真实删除
|
||||
|
||||
// 添加分类
|
||||
var category = new Category { Name = "测试分类" };
|
||||
@@ -483,10 +466,7 @@ public class _02_RepositoryCRUDTests
|
||||
.ToListAsync();
|
||||
|
||||
Console.WriteLine("✓ 按价格升序:");
|
||||
foreach (var p in ascProducts)
|
||||
{
|
||||
Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
}
|
||||
foreach (var p in ascProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
|
||||
// 按价格降序
|
||||
var descProducts = await repo.Query()
|
||||
@@ -494,10 +474,7 @@ public class _02_RepositoryCRUDTests
|
||||
.ToListAsync();
|
||||
|
||||
Console.WriteLine("✓ 按价格降序:");
|
||||
foreach (var p in descProducts)
|
||||
{
|
||||
Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
}
|
||||
foreach (var p in descProducts) Console.WriteLine($" - {p.Name}: {p.Price:C}");
|
||||
|
||||
Assert.AreEqual("A产品", ascProducts[0].Name);
|
||||
Assert.AreEqual("C产品", descProducts[0].Name);
|
||||
@@ -537,12 +514,11 @@ public class _02_RepositoryCRUDTests
|
||||
|
||||
Console.WriteLine("✓ 按价格区间分组统计:");
|
||||
foreach (var group in priceGroups)
|
||||
{
|
||||
Console.WriteLine($" - {group.PriceRange}: {group.Count}个产品, 平均价格 {group.AvgPrice:C}, 总库存 {group.TotalStock}");
|
||||
}
|
||||
Console.WriteLine(
|
||||
$" - {group.PriceRange}: {group.Count}个产品, 平均价格 {group.AvgPrice:C}, 总库存 {group.TotalStock}");
|
||||
|
||||
Assert.AreEqual(3, priceGroups.Count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,8 @@ public class _03_AuditFeatureTests
|
||||
// 创建启用审计功能的 DataContext
|
||||
var builder = new DataContextBuilder<TestDbContext>();
|
||||
builder.UseInMemoryDatabase($"AuditCreateDemo_{Guid.NewGuid()}")
|
||||
.UseAudit(true) // 启用审计
|
||||
.UseCurrentUser("zhang.san"); // 设置当前用户
|
||||
.UseAudit(true) // 启用审计
|
||||
.UseCurrentUser("zhang.san"); // 设置当前用户
|
||||
|
||||
using var db = builder.Build();
|
||||
var repo = db.Repository<Product>();
|
||||
@@ -49,7 +49,7 @@ public class _03_AuditFeatureTests
|
||||
Console.WriteLine($" CreatedBy: {product.CreatedBy ?? "(null)"}");
|
||||
|
||||
await repo.AddAsync(product);
|
||||
await db.SaveChangesAsync(); // SaveChanges 时自动填充审计信息
|
||||
await db.SaveChangesAsync(); // SaveChanges 时自动填充审计信息
|
||||
|
||||
var afterCreate = DateTime.UtcNow;
|
||||
|
||||
@@ -63,7 +63,7 @@ public class _03_AuditFeatureTests
|
||||
// 验证
|
||||
Assert.IsTrue(product.CreatedAt >= beforeCreate && product.CreatedAt <= afterCreate);
|
||||
Assert.AreEqual("zhang.san", product.CreatedBy);
|
||||
Assert.IsNull(product.UpdatedAt); // 创建时 UpdatedAt 为 null
|
||||
Assert.IsNull(product.UpdatedAt); // 创建时 UpdatedAt 为 null
|
||||
Assert.IsNull(product.UpdatedBy);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public class _03_AuditFeatureTests
|
||||
product.Name = "更新后的产品";
|
||||
product.Price = 200m;
|
||||
repo.Update(product);
|
||||
await db.SaveChangesAsync(); // SaveChanges 时自动填充 UpdatedAt 和 UpdatedBy
|
||||
await db.SaveChangesAsync(); // SaveChanges 时自动填充 UpdatedAt 和 UpdatedBy
|
||||
|
||||
Console.WriteLine("\n更新后的审计信息:");
|
||||
Console.WriteLine($" CreatedBy: {product.CreatedBy} (保持不变)");
|
||||
@@ -117,11 +117,11 @@ public class _03_AuditFeatureTests
|
||||
Console.WriteLine($" ✓ UpdatedAt: {product.UpdatedAt:yyyy-MM-dd HH:mm:ss}");
|
||||
|
||||
// 验证
|
||||
Assert.AreEqual(createdBy, product.CreatedBy); // 创建人不变
|
||||
Assert.AreEqual(createdAt, product.CreatedAt); // 创建时间不变
|
||||
Assert.AreEqual("editor", product.UpdatedBy); // 更新人是新用户
|
||||
Assert.AreEqual(createdBy, product.CreatedBy); // 创建人不变
|
||||
Assert.AreEqual(createdAt, product.CreatedAt); // 创建时间不变
|
||||
Assert.AreEqual("editor", product.UpdatedBy); // 更新人是新用户
|
||||
Assert.IsNotNull(product.UpdatedAt);
|
||||
Assert.IsTrue(product.UpdatedAt > product.CreatedAt); // 更新时间晚于创建时间
|
||||
Assert.IsTrue(product.UpdatedAt > product.CreatedAt); // 更新时间晚于创建时间
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,9 +167,9 @@ public class _03_AuditFeatureTests
|
||||
Console.WriteLine($"第2次更新: {product.UpdatedBy} 于 {product.UpdatedAt:HH:mm:ss}");
|
||||
|
||||
// 验证
|
||||
Assert.AreEqual("user1", product.CreatedBy); // 创建人始终不变
|
||||
Assert.AreEqual("user3", product.UpdatedBy); // 最后更新人
|
||||
Assert.IsTrue(product.UpdatedAt > firstUpdateTime); // 更新时间在变化
|
||||
Assert.AreEqual("user1", product.CreatedBy); // 创建人始终不变
|
||||
Assert.AreEqual("user3", product.UpdatedBy); // 最后更新人
|
||||
Assert.IsTrue(product.UpdatedAt > firstUpdateTime); // 更新时间在变化
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -215,8 +215,8 @@ public class _03_AuditFeatureTests
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
Console.WriteLine($"✓ 更新人: {product.UpdatedBy}");
|
||||
Assert.AreEqual("zhang.san", product.CreatedBy); // 创建人不变
|
||||
Assert.AreEqual("li.si", product.UpdatedBy); // 更新人改变
|
||||
Assert.AreEqual("zhang.san", product.CreatedBy); // 创建人不变
|
||||
Assert.AreEqual("li.si", product.UpdatedBy); // 更新人改变
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -263,7 +263,7 @@ public class _03_AuditFeatureTests
|
||||
{
|
||||
var builder = new DataContextBuilder<TestDbContext>();
|
||||
builder.UseInMemoryDatabase($"NoAuditDemo_{Guid.NewGuid()}")
|
||||
.UseAudit(true) // 即使启用了审计功能
|
||||
.UseAudit(true) // 即使启用了审计功能
|
||||
.UseCurrentUser("admin");
|
||||
|
||||
using var db = builder.Build();
|
||||
@@ -290,7 +290,7 @@ public class _03_AuditFeatureTests
|
||||
{
|
||||
var builder = new DataContextBuilder<TestDbContext>();
|
||||
builder.UseInMemoryDatabase($"DisableAuditDemo_{Guid.NewGuid()}")
|
||||
.UseAudit(false) // 禁用审计功能
|
||||
.UseAudit(false) // 禁用审计功能
|
||||
.UseCurrentUser("admin");
|
||||
|
||||
using var db = builder.Build();
|
||||
@@ -368,4 +368,4 @@ public class _03_AuditFeatureTests
|
||||
Console.WriteLine($" - 谁最后修改:{product.UpdatedBy}");
|
||||
Console.WriteLine($" - 何时修改:{product.UpdatedAt:yyyy-MM-dd HH:mm:ss}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class _04_SoftDeleteTests
|
||||
var builder = new DataContextBuilder<TestDbContext>();
|
||||
builder.UseInMemoryDatabase($"SoftDeleteDemo_{Guid.NewGuid()}")
|
||||
.UseAudit(true)
|
||||
.UseSoftDelete(true) // 启用软删除
|
||||
.UseSoftDelete(true) // 启用软删除
|
||||
.UseCurrentUser("admin");
|
||||
|
||||
using var db = builder.Build();
|
||||
@@ -71,7 +71,7 @@ public class _04_SoftDeleteTests
|
||||
|
||||
// 但数据仍在数据库中
|
||||
var allIncludingDeleted = await db.Context.Set<Product>()
|
||||
.IgnoreQueryFilters() // 忽略软删除过滤器
|
||||
.IgnoreQueryFilters() // 忽略软删除过滤器
|
||||
.Where(p => p.Id == productId)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
@@ -147,15 +147,13 @@ public class _04_SoftDeleteTests
|
||||
var repo = db.Repository<Product>();
|
||||
|
||||
// 添加 5 个产品
|
||||
for (int i = 1; i <= 5; i++)
|
||||
{
|
||||
for (var i = 1; i <= 5; i++)
|
||||
await repo.AddAsync(new Product
|
||||
{
|
||||
Name = $"产品{i}",
|
||||
Price = i * 100m,
|
||||
Stock = i * 10
|
||||
});
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
Console.WriteLine("✓ 创建了 5 个产品");
|
||||
@@ -264,15 +262,13 @@ public class _04_SoftDeleteTests
|
||||
|
||||
// 添加多个产品
|
||||
var products = new List<Product>();
|
||||
for (int i = 1; i <= 10; i++)
|
||||
{
|
||||
for (var i = 1; i <= 10; i++)
|
||||
products.Add(new Product
|
||||
{
|
||||
Name = $"产品{i}",
|
||||
Price = i * 100m,
|
||||
Stock = i * 10
|
||||
});
|
||||
}
|
||||
await repo.AddRangeAsync(products);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
@@ -290,10 +286,7 @@ public class _04_SoftDeleteTests
|
||||
Console.WriteLine($"✓ 剩余可见产品: {remaining.Count} 个");
|
||||
Assert.AreEqual(5, remaining.Count);
|
||||
|
||||
foreach (var p in expensiveProducts)
|
||||
{
|
||||
Assert.IsTrue(p.IsDeleted);
|
||||
}
|
||||
foreach (var p in expensiveProducts) Assert.IsTrue(p.IsDeleted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -343,7 +336,7 @@ public class _04_SoftDeleteTests
|
||||
{
|
||||
var builder = new DataContextBuilder<TestDbContext>();
|
||||
builder.UseInMemoryDatabase($"DisableSoftDelete_{Guid.NewGuid()}")
|
||||
.UseSoftDelete(false) // 禁用软删除
|
||||
.UseSoftDelete(false) // 禁用软删除
|
||||
.UseCurrentUser("admin");
|
||||
|
||||
using var db = builder.Build();
|
||||
@@ -371,12 +364,8 @@ public class _04_SoftDeleteTests
|
||||
.FirstOrDefaultAsync(p => p.Id == productId);
|
||||
|
||||
if (found != null)
|
||||
{
|
||||
Console.WriteLine($" 结果:软删除 (IsDeleted={found.IsDeleted})");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($" 结果:物理删除");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,7 @@ public class _05_PaginationTests
|
||||
// 添加测试数据:100 个产品
|
||||
var repo = _db.Repository<Product>();
|
||||
var products = new List<Product>();
|
||||
for (int i = 1; i <= 100; i++)
|
||||
{
|
||||
for (var i = 1; i <= 100; i++)
|
||||
products.Add(new Product
|
||||
{
|
||||
Name = $"产品{i:D3}",
|
||||
@@ -39,7 +38,6 @@ public class _05_PaginationTests
|
||||
Stock = i * 5,
|
||||
Description = i % 2 == 0 ? "热门产品" : "普通产品"
|
||||
});
|
||||
}
|
||||
await repo.AddRangeAsync(products);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
@@ -62,8 +60,8 @@ public class _05_PaginationTests
|
||||
|
||||
// 查询第 1 页,每页 10 条
|
||||
var page1 = await repo.GetPagedAsync(
|
||||
page: 1,
|
||||
pageSize: 10);
|
||||
1,
|
||||
10);
|
||||
|
||||
Console.WriteLine($"第 1 页:");
|
||||
Console.WriteLine($" 当前页: {page1.PageIndex}");
|
||||
@@ -83,10 +81,7 @@ public class _05_PaginationTests
|
||||
Assert.IsTrue(page1.HasNextPage);
|
||||
|
||||
Console.WriteLine($"\n产品列表:");
|
||||
foreach (var product in page1.Items)
|
||||
{
|
||||
Console.WriteLine($" - {product.Name}: {product.Price:C}");
|
||||
}
|
||||
foreach (var product in page1.Items) Console.WriteLine($" - {product.Name}: {product.Price:C}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,8 +91,8 @@ public class _05_PaginationTests
|
||||
public async Task Demo_IterateAllPages()
|
||||
{
|
||||
var repo = _db.Repository<Product>();
|
||||
int pageSize = 15;
|
||||
int currentPage = 1;
|
||||
var pageSize = 15;
|
||||
var currentPage = 1;
|
||||
|
||||
Console.WriteLine($"=== 遍历所有页(每页 {pageSize} 条)===\n");
|
||||
|
||||
@@ -107,7 +102,8 @@ public class _05_PaginationTests
|
||||
pageResult = await repo.GetPagedAsync(currentPage, pageSize);
|
||||
|
||||
Console.WriteLine($"第 {currentPage} 页: {pageResult.Items.Count} 条记录");
|
||||
Console.WriteLine($" 范围: {(currentPage - 1) * pageSize + 1} - {Math.Min(currentPage * pageSize, pageResult.TotalCount)}");
|
||||
Console.WriteLine(
|
||||
$" 范围: {(currentPage - 1) * pageSize + 1} - {Math.Min(currentPage * pageSize, pageResult.TotalCount)}");
|
||||
|
||||
// 处理当前页数据
|
||||
foreach (var product in pageResult.Items)
|
||||
@@ -116,11 +112,10 @@ public class _05_PaginationTests
|
||||
}
|
||||
|
||||
currentPage++;
|
||||
|
||||
} while (pageResult.HasNextPage);
|
||||
|
||||
Console.WriteLine($"\n✓ 总共遍历了 {currentPage - 1} 页");
|
||||
Assert.AreEqual(7, currentPage - 1); // 100 / 15 = 7 页
|
||||
Assert.AreEqual(7, currentPage - 1); // 100 / 15 = 7 页
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -133,9 +128,9 @@ public class _05_PaginationTests
|
||||
|
||||
// 查询价格 > 500 的产品,第 1 页,每页 10 条
|
||||
var result = await repo.GetPagedAsync(
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
predicate: p => p.Price > 500m);
|
||||
1,
|
||||
10,
|
||||
p => p.Price > 500m);
|
||||
|
||||
Console.WriteLine($"查询条件: 价格 > 500");
|
||||
Console.WriteLine($" 总记录数: {result.TotalCount}");
|
||||
@@ -160,23 +155,18 @@ public class _05_PaginationTests
|
||||
|
||||
// 按价格降序排列
|
||||
var result = await repo.GetPagedAsync(
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
predicate: null,
|
||||
orderBy: q => q.OrderByDescending(p => p.Price));
|
||||
1,
|
||||
10,
|
||||
null,
|
||||
q => q.OrderByDescending(p => p.Price));
|
||||
|
||||
Console.WriteLine($"排序: 按价格降序");
|
||||
Console.WriteLine($"\n前 10 个最贵的产品:");
|
||||
foreach (var product in result.Items)
|
||||
{
|
||||
Console.WriteLine($" - {product.Name}: {product.Price:C}");
|
||||
}
|
||||
foreach (var product in result.Items) Console.WriteLine($" - {product.Name}: {product.Price:C}");
|
||||
|
||||
// 验证排序
|
||||
for (int i = 0; i < result.Items.Count - 1; i++)
|
||||
{
|
||||
for (var i = 0; i < result.Items.Count - 1; i++)
|
||||
Assert.IsTrue(result.Items[i].Price >= result.Items[i + 1].Price);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -189,10 +179,10 @@ public class _05_PaginationTests
|
||||
|
||||
// 查询热门产品,价格 > 300,按库存降序,第 2 页,每页 5 条
|
||||
var result = await repo.GetPagedAsync(
|
||||
page: 2,
|
||||
pageSize: 5,
|
||||
predicate: p => p.Description == "热门产品" && p.Price > 300m,
|
||||
orderBy: q => q.OrderByDescending(p => p.Stock));
|
||||
2,
|
||||
5,
|
||||
p => p.Description == "热门产品" && p.Price > 300m,
|
||||
q => q.OrderByDescending(p => p.Stock));
|
||||
|
||||
Console.WriteLine($"复杂查询:");
|
||||
Console.WriteLine($" 条件: 热门产品 AND 价格>300");
|
||||
@@ -234,8 +224,8 @@ public class _05_PaginationTests
|
||||
Console.WriteLine($"有下一页: {result.HasNextPage}");
|
||||
|
||||
// 计算记录范围
|
||||
int startIndex = (result.PageIndex - 1) * result.PageSize + 1;
|
||||
int endIndex = Math.Min(result.PageIndex * result.PageSize, result.TotalCount);
|
||||
var startIndex = (result.PageIndex - 1) * result.PageSize + 1;
|
||||
var endIndex = Math.Min(result.PageIndex * result.PageSize, result.TotalCount);
|
||||
Console.WriteLine($"\n记录范围: {startIndex} - {endIndex}");
|
||||
|
||||
// 验证
|
||||
@@ -256,9 +246,9 @@ public class _05_PaginationTests
|
||||
|
||||
// 查询不存在的条件
|
||||
var result = await repo.GetPagedAsync(
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
predicate: p => p.Price > 99999m);
|
||||
1,
|
||||
10,
|
||||
p => p.Price > 99999m);
|
||||
|
||||
Console.WriteLine($"查询不存在的记录:");
|
||||
Console.WriteLine($" 总记录数: {result.TotalCount}");
|
||||
@@ -306,9 +296,9 @@ public class _05_PaginationTests
|
||||
var repo = _db.Repository<Product>();
|
||||
|
||||
// 模拟用户请求
|
||||
int requestedPage = 3;
|
||||
int pageSize = 20;
|
||||
string? searchTerm = "产品0"; // 用户搜索
|
||||
var requestedPage = 3;
|
||||
var pageSize = 20;
|
||||
var searchTerm = "产品0"; // 用户搜索
|
||||
|
||||
Console.WriteLine($"=== UI 分页场景 ===");
|
||||
Console.WriteLine($"用户请求: 第 {requestedPage} 页, 每页 {pageSize} 条");
|
||||
@@ -316,12 +306,12 @@ public class _05_PaginationTests
|
||||
|
||||
// 执行分页查询
|
||||
var result = await repo.GetPagedAsync(
|
||||
page: requestedPage,
|
||||
pageSize: pageSize,
|
||||
predicate: string.IsNullOrEmpty(searchTerm)
|
||||
requestedPage,
|
||||
pageSize,
|
||||
string.IsNullOrEmpty(searchTerm)
|
||||
? null
|
||||
: p => p.Name.Contains(searchTerm),
|
||||
orderBy: q => q.OrderBy(p => p.Name));
|
||||
q => q.OrderBy(p => p.Name));
|
||||
|
||||
// 构建返回给前端的数据
|
||||
var uiData = new
|
||||
@@ -387,8 +377,8 @@ public class _05_PaginationTests
|
||||
.OrderBy(p => p.Name);
|
||||
|
||||
// 手动实现分页逻辑
|
||||
int page = 2;
|
||||
int pageSize = 10;
|
||||
var page = 2;
|
||||
var pageSize = 10;
|
||||
|
||||
var totalCount = await query.CountAsync();
|
||||
var items = await query
|
||||
@@ -412,4 +402,4 @@ public class _05_PaginationTests
|
||||
|
||||
Console.WriteLine($"\n✓ 可以直接使用 IQueryable 和 PagedResult 进行自定义分页");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,10 +118,7 @@ public class _06_CustomEntityTests
|
||||
// 列出所有地区
|
||||
var allRegions = await regions.ToListAsync();
|
||||
Console.WriteLine($"\n所有地区:");
|
||||
foreach (var region in allRegions)
|
||||
{
|
||||
Console.WriteLine($" [{region.Code}] {region.Name}");
|
||||
}
|
||||
foreach (var region in allRegions) Console.WriteLine($" [{region.Code}] {region.Name}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -155,7 +152,7 @@ public class _06_CustomEntityTests
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
Console.WriteLine($" ID: {tag.Id}, Name: {tag.Name}, Color: {tag.Color}");
|
||||
Assert.IsTrue(tag.Id > 0); // 自增 Id
|
||||
Assert.IsTrue(tag.Id > 0); // 自增 Id
|
||||
}
|
||||
|
||||
// 查询
|
||||
@@ -306,8 +303,7 @@ public class _06_CustomEntityTests
|
||||
var repo = db.Repository<CustomProduct>();
|
||||
|
||||
// 添加测试数据
|
||||
for (int i = 1; i <= 20; i++)
|
||||
{
|
||||
for (var i = 1; i <= 20; i++)
|
||||
await repo.AddAsync(new CustomProduct
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
@@ -315,7 +311,6 @@ public class _06_CustomEntityTests
|
||||
Price = i * 100m,
|
||||
CreatedDate = DateTime.UtcNow.AddDays(-i)
|
||||
});
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
Console.WriteLine("=== 自定义实体的查询 ===\n");
|
||||
@@ -326,7 +321,7 @@ public class _06_CustomEntityTests
|
||||
|
||||
// 2. 使用业务属性查询
|
||||
var veryExpensive = await repo.Query()
|
||||
.Where(p => p.IsExpensive) // 使用计算属性
|
||||
.Where(p => p.IsExpensive) // 使用计算属性
|
||||
.ToListAsync();
|
||||
Console.WriteLine($"2. 使用 IsExpensive 属性: {veryExpensive.Count} 个");
|
||||
|
||||
@@ -382,4 +377,4 @@ public class _06_CustomEntityTests
|
||||
Console.WriteLine(" 你可以完全自定义,仍然享受仓储模式的便利");
|
||||
Console.WriteLine(" 灵活性和便利性可以兼得!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ public class _07_EFCoreDirectUsageTests
|
||||
var product3 = new Product { Name = "产品3", Price = 300m, Stock = 30 };
|
||||
await productRepo.AddAsync(product2);
|
||||
await productRepo.AddAsync(product3);
|
||||
await db.SaveChangesAsync(); // 两个产品作为一个事务提交
|
||||
await db.SaveChangesAsync(); // 两个产品作为一个事务提交
|
||||
|
||||
Console.WriteLine($" ✓ 隐式事务添加了 2 个产品");
|
||||
|
||||
@@ -233,15 +233,13 @@ public class _07_EFCoreDirectUsageTests
|
||||
|
||||
Console.WriteLine("1. 批量插入(推荐方式):");
|
||||
var products = new List<Product>();
|
||||
for (int i = 1; i <= 1000; i++)
|
||||
{
|
||||
for (var i = 1; i <= 1000; i++)
|
||||
products.Add(new Product
|
||||
{
|
||||
Name = $"产品{i}",
|
||||
Price = i * 10m,
|
||||
Stock = i
|
||||
});
|
||||
}
|
||||
|
||||
var startTime = DateTime.UtcNow;
|
||||
|
||||
@@ -288,15 +286,13 @@ public class _07_EFCoreDirectUsageTests
|
||||
var repo = db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
for (int i = 1; i <= 100; i++)
|
||||
{
|
||||
for (var i = 1; i <= 100; i++)
|
||||
await repo.AddAsync(new Product
|
||||
{
|
||||
Name = $"产品{i}",
|
||||
Price = i * 10m,
|
||||
Stock = i
|
||||
});
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
Console.WriteLine("=== AsNoTracking 优化 ===\n");
|
||||
@@ -310,14 +306,14 @@ public class _07_EFCoreDirectUsageTests
|
||||
|
||||
Console.WriteLine("\n2. AsNoTracking 查询(不跟踪):");
|
||||
var untrackedProducts = await db.Context.Set<Product>()
|
||||
.AsNoTracking() // 不跟踪实体变化
|
||||
.AsNoTracking() // 不跟踪实体变化
|
||||
.Take(10)
|
||||
.ToListAsync();
|
||||
Console.WriteLine($" ✓ 查询 {untrackedProducts.Count} 条,实体不被跟踪");
|
||||
Console.WriteLine($" 适用于: 只读查询、数据展示");
|
||||
|
||||
Console.WriteLine("\n3. 仓储默认支持:");
|
||||
var query = repo.Query(trackChanges: false); // 指定不跟踪
|
||||
var query = repo.Query(false); // 指定不跟踪
|
||||
var products = await query.Take(10).ToListAsync();
|
||||
Console.WriteLine($" ✓ 仓储的 Query() 方法支持 trackChanges 参数");
|
||||
|
||||
@@ -354,21 +350,22 @@ public class _07_EFCoreDirectUsageTests
|
||||
|
||||
var entry = db.Context.Entry(product);
|
||||
Console.WriteLine($"1. 新增状态:");
|
||||
Console.WriteLine($" EntityState: {entry.State}"); // Added
|
||||
Console.WriteLine($" EntityState: {entry.State}"); // Added
|
||||
Assert.AreEqual(EntityState.Added, entry.State);
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
Console.WriteLine($"\n2. 保存后状态:");
|
||||
Console.WriteLine($" EntityState: {entry.State}"); // Unchanged
|
||||
Console.WriteLine($" EntityState: {entry.State}"); // Unchanged
|
||||
Assert.AreEqual(EntityState.Unchanged, entry.State);
|
||||
|
||||
// 修改实体
|
||||
product.Price = 200m;
|
||||
|
||||
Console.WriteLine($"\n3. 修改后状态:");
|
||||
Console.WriteLine($" EntityState: {entry.State}"); // Modified
|
||||
Console.WriteLine($" 修改的属性: {string.Join(", ", entry.Properties.Where(p => p.IsModified).Select(p => p.Metadata.Name))}");
|
||||
Console.WriteLine($" EntityState: {entry.State}"); // Modified
|
||||
Console.WriteLine(
|
||||
$" 修改的属性: {string.Join(", ", entry.Properties.Where(p => p.IsModified).Select(p => p.Metadata.Name))}");
|
||||
Assert.AreEqual(EntityState.Modified, entry.State);
|
||||
|
||||
// 查看原始值和当前值
|
||||
@@ -396,8 +393,7 @@ public class _07_EFCoreDirectUsageTests
|
||||
var repo = db.Repository<Product>();
|
||||
|
||||
// 添加测试数据
|
||||
for (int i = 1; i <= 50; i++)
|
||||
{
|
||||
for (var i = 1; i <= 50; i++)
|
||||
await repo.AddAsync(new Product
|
||||
{
|
||||
Name = $"产品{i}",
|
||||
@@ -405,7 +401,6 @@ public class _07_EFCoreDirectUsageTests
|
||||
Stock = i * 2,
|
||||
Description = i % 2 == 0 ? "热门" : "普通"
|
||||
});
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
Console.WriteLine("=== 高级查询技巧 ===\n");
|
||||
@@ -439,9 +434,7 @@ public class _07_EFCoreDirectUsageTests
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var stat in groupStats)
|
||||
{
|
||||
Console.WriteLine($" {stat.Category}: {stat.Count}个, 均价 {stat.AvgPrice:C}, 最大库存 {stat.MaxStock}");
|
||||
}
|
||||
|
||||
// 3. 子查询
|
||||
Console.WriteLine("\n3. 子查询:");
|
||||
@@ -493,4 +486,4 @@ public class _07_EFCoreDirectUsageTests
|
||||
Console.WriteLine(" 两者可以自由组合使用,根据场景选择");
|
||||
Console.WriteLine(" 底层完全共用同一个 DbContext,无缝协作");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Sharp\Data\Data.csproj" />
|
||||
<ProjectReference Include="..\..\src\Sharp\Common\Common.csproj" />
|
||||
<ProjectReference Include="..\..\src\Sharp\Data\Data.csproj"/>
|
||||
<ProjectReference Include="..\..\src\Sharp\Common\Common.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+20
-20
@@ -6,17 +6,17 @@
|
||||
|
||||
## 测试文件说明
|
||||
|
||||
| 文件 | 说明 | 主要演示内容 |
|
||||
|------|------|------------|
|
||||
| `TestEntities.cs` | 实体定义演示 | 6种不同的实体定义方式 |
|
||||
| `TestDbContext.cs` | DbContext 配置演示 | 如何配置各种实体 |
|
||||
| `01_BasicUsageTests.cs` | 基础使用 | 3行代码快速开始、各种配置选项 |
|
||||
| `02_RepositoryCRUDTests.cs` | 仓储 CRUD | 增删改查、批量操作、复杂查询 |
|
||||
| `03_AuditFeatureTests.cs` | 审计功能 | 自动记录创建/修改信息 |
|
||||
| `04_SoftDeleteTests.cs` | 软删除功能 | 逻辑删除 vs 物理删除 |
|
||||
| `05_PaginationTests.cs` | 分页查询 | 各种分页场景 |
|
||||
| `06_CustomEntityTests.cs` | 自定义实体 | 不使用基类的灵活方式 |
|
||||
| `07_EFCoreDirectUsageTests.cs` | EF Core 直接使用 | 原生 SQL、事务、高级查询 |
|
||||
| 文件 | 说明 | 主要演示内容 |
|
||||
|--------------------------------|----------------|-----------------|
|
||||
| `TestEntities.cs` | 实体定义演示 | 6种不同的实体定义方式 |
|
||||
| `TestDbContext.cs` | DbContext 配置演示 | 如何配置各种实体 |
|
||||
| `01_BasicUsageTests.cs` | 基础使用 | 3行代码快速开始、各种配置选项 |
|
||||
| `02_RepositoryCRUDTests.cs` | 仓储 CRUD | 增删改查、批量操作、复杂查询 |
|
||||
| `03_AuditFeatureTests.cs` | 审计功能 | 自动记录创建/修改信息 |
|
||||
| `04_SoftDeleteTests.cs` | 软删除功能 | 逻辑删除 vs 物理删除 |
|
||||
| `05_PaginationTests.cs` | 分页查询 | 各种分页场景 |
|
||||
| `06_CustomEntityTests.cs` | 自定义实体 | 不使用基类的灵活方式 |
|
||||
| `07_EFCoreDirectUsageTests.cs` | EF Core 直接使用 | 原生 SQL、事务、高级查询 |
|
||||
|
||||
## 运行测试
|
||||
|
||||
@@ -165,19 +165,19 @@ using (var dbB = CreateDataContext("userB"))
|
||||
## 最佳实践
|
||||
|
||||
1. **根据需求选择实体定义方式**
|
||||
- 需要审计+软删除:使用 `AuditableEntity`
|
||||
- 只需要基础 CRUD:使用 `Entity` 或完全自定义
|
||||
- 已有实体模型:保持原样,直接使用
|
||||
- 需要审计+软删除:使用 `AuditableEntity`
|
||||
- 只需要基础 CRUD:使用 `Entity` 或完全自定义
|
||||
- 已有实体模型:保持原样,直接使用
|
||||
|
||||
2. **性能优化**
|
||||
- 只读查询使用 `AsNoTracking()`
|
||||
- 批量操作使用 `AddRange/UpdateRange/RemoveRange`
|
||||
- 避免在循环中调用 `SaveChangesAsync`
|
||||
- 只读查询使用 `AsNoTracking()`
|
||||
- 批量操作使用 `AddRange/UpdateRange/RemoveRange`
|
||||
- 避免在循环中调用 `SaveChangesAsync`
|
||||
|
||||
3. **灵活使用**
|
||||
- 简单场景用仓储
|
||||
- 复杂查询直接用 EF Core
|
||||
- 两者可以无缝混用
|
||||
- 简单场景用仓储
|
||||
- 复杂查询直接用 EF Core
|
||||
- 两者可以无缝混用
|
||||
|
||||
## 问题反馈
|
||||
|
||||
|
||||
@@ -180,4 +180,4 @@ public class TestDbContext : DbContext
|
||||
entity.HasIndex(e => e.Email);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,4 +156,4 @@ public class Address
|
||||
public string Country { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
Reference in new issue
Block a user