27 KiB
27 KiB
阶段4:应用程序集成和EF Core适配
阶段概述
时间: 1天
目标: 配置.NET 8应用程序连接SQL Server,创建EF Core实体模型,适配API接口
优先级: P0 (最高优先级)
详细任务清单
4.1 EF Core 8.0配置 (0.3天)
任务描述
配置Entity Framework Core 8.0连接SQL Server数据库
具体工作
- 安装EF Core SQL Server包
- 配置连接字符串
- 创建DbContext
- 配置依赖注入
EF Core配置
1. NuGet包安装
<!-- 在.csproj文件中添加 -->
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0" />
2. 连接字符串配置
// appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=honey_box;Trusted_Connection=true;TrustServerCertificate=true;MultipleActiveResultSets=true;Encrypt=false",
"ReadOnlyConnection": "Server=localhost;Database=honey_box;User Id=honey_box_readonly;Password=HoneyBoxRead2024!@#;TrustServerCertificate=true;Encrypt=false"
},
"DatabaseSettings": {
"CommandTimeout": 30,
"EnableSensitiveDataLogging": false,
"EnableDetailedErrors": false
}
}
// appsettings.Development.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=honey_box_dev;Trusted_Connection=true;TrustServerCertificate=true;MultipleActiveResultSets=true;Encrypt=false"
},
"DatabaseSettings": {
"EnableSensitiveDataLogging": true,
"EnableDetailedErrors": true
}
}
3. DbContext配置
// Data/HoneyBoxDbContext.cs
using Microsoft.EntityFrameworkCore;
using HoneyBox.Core.Entities;
namespace HoneyBox.Data
{
public class HoneyBoxDbContext : DbContext
{
public HoneyBoxDbContext(DbContextOptions<HoneyBoxDbContext> options) : base(options)
{
}
// 用户相关
public DbSet<User> Users { get; set; }
public DbSet<UserAccount> UserAccounts { get; set; }
public DbSet<UserLoginLog> UserLoginLogs { get; set; }
// 商品相关
public DbSet<Goods> Goods { get; set; }
public DbSet<GoodsItem> GoodsItems { get; set; }
public DbSet<GoodsType> GoodsTypes { get; set; }
public DbSet<GoodsExtension> GoodsExtensions { get; set; }
// 订单相关
public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
// 财务相关
public DbSet<BalanceTransaction> BalanceTransactions { get; set; }
public DbSet<IntegralTransaction> IntegralTransactions { get; set; }
public DbSet<PaymentRecord> PaymentRecords { get; set; }
// 优惠券和任务
public DbSet<CouponTemplate> CouponTemplates { get; set; }
public DbSet<UserCoupon> UserCoupons { get; set; }
public DbSet<TaskConfig> TaskConfigs { get; set; }
public DbSet<UserTaskRecord> UserTaskRecords { get; set; }
// 系统配置
public DbSet<PrizeLevel> PrizeLevels { get; set; }
public DbSet<SystemConfig> SystemConfigs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 应用所有配置
modelBuilder.ApplyConfigurationsFromAssembly(typeof(HoneyBoxDbContext).Assembly);
// 全局查询过滤器
modelBuilder.Entity<User>().HasQueryFilter(u => u.Status != 0);
modelBuilder.Entity<Goods>().HasQueryFilter(g => g.DeletedAt == null);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
// 仅在未配置时使用默认连接
optionsBuilder.UseSqlServer("Server=localhost;Database=honey_box;Trusted_Connection=true;");
}
}
}
}
4. 依赖注入配置
// Program.cs
using Microsoft.EntityFrameworkCore;
using HoneyBox.Data;
var builder = WebApplication.CreateBuilder(args);
// 数据库配置
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var databaseSettings = builder.Configuration.GetSection("DatabaseSettings");
builder.Services.AddDbContext<HoneyBoxDbContext>(options =>
{
options.UseSqlServer(connectionString, sqlOptions =>
{
sqlOptions.CommandTimeout(databaseSettings.GetValue<int>("CommandTimeout", 30));
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(5),
errorNumbersToAdd: null);
});
if (builder.Environment.IsDevelopment())
{
options.EnableSensitiveDataLogging(databaseSettings.GetValue<bool>("EnableSensitiveDataLogging", false));
options.EnableDetailedErrors(databaseSettings.GetValue<bool>("EnableDetailedErrors", false));
}
});
// 只读数据库上下文(用于报表查询)
builder.Services.AddDbContext<HoneyBoxReadOnlyDbContext>(options =>
{
var readOnlyConnection = builder.Configuration.GetConnectionString("ReadOnlyConnection");
options.UseSqlServer(readOnlyConnection, sqlOptions =>
{
sqlOptions.CommandTimeout(60); // 报表查询超时时间更长
});
});
var app = builder.Build();
// 数据库迁移(仅在开发环境)
if (app.Environment.IsDevelopment())
{
using var scope = app.Services.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<HoneyBoxDbContext>();
context.Database.EnsureCreated();
}
app.Run();
4.2 实体模型创建 (0.4天)
任务描述
创建符合snake_case数据库结构的EF Core实体模型
具体工作
- 创建实体类
- 配置实体映射
- 设置导航属性
- 配置索引和约束
实体模型设计
1. 用户实体
// Entities/User.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace HoneyBox.Core.Entities
{
[Table("users")]
public class User
{
[Key]
[Column("id")]
public int Id { get; set; }
[Required]
[MaxLength(50)]
[Column("open_id")]
public string OpenId { get; set; } = string.Empty;
[MaxLength(255)]
[Column("union_id")]
public string? UnionId { get; set; }
[MaxLength(255)]
[Column("gzh_open_id")]
public string? GzhOpenId { get; set; }
[MaxLength(15)]
[Column("mobile")]
public string? Mobile { get; set; }
[Required]
[MaxLength(255)]
[Column("nickname")]
public string Nickname { get; set; } = string.Empty;
[Required]
[MaxLength(500)]
[Column("head_img")]
public string HeadImg { get; set; } = string.Empty;
[Column("parent_id")]
public int ParentId { get; set; } = 0;
[Column("money", TypeName = "decimal(18,2)")]
public decimal Money { get; set; } = 0;
[Column("money2", TypeName = "decimal(18,2)")]
public decimal Money2 { get; set; } = 0;
[Column("integral", TypeName = "decimal(18,2)")]
public decimal Integral { get; set; } = 0;
[Column("score", TypeName = "decimal(18,2)")]
public decimal Score { get; set; } = 0;
[Column("ou_qi")]
public int OuQi { get; set; } = 0;
[Column("ou_qi_level")]
public int OuQiLevel { get; set; } = 0;
[Column("vip_level")]
public byte VipLevel { get; set; } = 1;
[Column("status")]
public byte Status { get; set; } = 1;
[Column("is_test")]
public int IsTest { get; set; } = 0;
[Required]
[MaxLength(16)]
[Column("uid")]
public string Uid { get; set; } = string.Empty;
[Column("click_id")]
public int? ClickId { get; set; }
[Column("created_at")]
public DateTime CreatedAt { get; set; } = DateTime.Now;
[Column("updated_at")]
public DateTime UpdatedAt { get; set; } = DateTime.Now;
[Column("last_login_at")]
public DateTime? LastLoginAt { get; set; }
// 导航属性
public virtual UserAccount? Account { get; set; }
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
public virtual ICollection<UserCoupon> Coupons { get; set; } = new List<UserCoupon>();
public virtual ICollection<UserTaskRecord> TaskRecords { get; set; } = new List<UserTaskRecord>();
}
}
2. 商品实体
// Entities/Goods.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace HoneyBox.Core.Entities
{
[Table("goods")]
public class Goods
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("category_id")]
public int CategoryId { get; set; } = 0;
[Required]
[MaxLength(255)]
[Column("title")]
public string Title { get; set; } = string.Empty;
[Required]
[MaxLength(500)]
[Column("img_url")]
public string ImgUrl { get; set; } = string.Empty;
[Required]
[MaxLength(500)]
[Column("img_url_detail")]
public string ImgUrlDetail { get; set; } = string.Empty;
[Column("price", TypeName = "decimal(18,2)")]
public decimal Price { get; set; } = 0;
[Column("stock")]
public int Stock { get; set; } = 0;
[Column("sale_stock")]
public int SaleStock { get; set; } = 0;
[Column("type")]
public byte Type { get; set; } = 0;
[Column("status")]
public byte Status { get; set; } = 1;
[Column("is_lock")]
public byte IsLock { get; set; } = 0;
[Column("lock_time")]
public int LockTime { get; set; } = 0;
[Column("is_discount")]
public byte IsDiscount { get; set; } = 0;
[Column("is_new")]
public byte IsNew { get; set; } = 0;
[Column("is_show")]
public byte IsShow { get; set; } = 0;
[Column("unlock_amount", TypeName = "decimal(18,2)")]
public decimal UnlockAmount { get; set; } = 0;
[Column("daily_limit")]
public int DailyLimit { get; set; } = 0;
[Column("global_limit")]
public int GlobalLimit { get; set; } = 0;
[Column("sort_order")]
public int SortOrder { get; set; } = 1;
[Column("sale_time")]
public DateTime? SaleTime { get; set; }
[Column("created_at")]
public DateTime CreatedAt { get; set; } = DateTime.Now;
[Column("updated_at")]
public DateTime UpdatedAt { get; set; } = DateTime.Now;
[Column("deleted_at")]
public DateTime? DeletedAt { get; set; }
// 导航属性
public virtual ICollection<GoodsItem> Items { get; set; } = new List<GoodsItem>();
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
public virtual GoodsExtension? Extension { get; set; }
}
}
3. 订单实体
// Entities/Order.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace HoneyBox.Core.Entities
{
[Table("orders")]
public class Order
{
[Key]
[Column("id")]
public int Id { get; set; }
[Required]
[MaxLength(60)]
[Column("order_no")]
public string OrderNo { get; set; } = string.Empty;
[Column("user_id")]
public int UserId { get; set; }
[Column("goods_id")]
public int GoodsId { get; set; }
[Column("box_number")]
public int BoxNumber { get; set; }
[Required]
[MaxLength(255)]
[Column("goods_title")]
public string GoodsTitle { get; set; } = string.Empty;
[MaxLength(500)]
[Column("goods_img_url")]
public string? GoodsImgUrl { get; set; }
[Column("order_type")]
public byte OrderType { get; set; } = 0;
[Column("order_total", TypeName = "decimal(18,2)")]
public decimal OrderTotal { get; set; }
[Column("discount_total", TypeName = "decimal(18,2)")]
public decimal DiscountTotal { get; set; }
[Column("final_price", TypeName = "decimal(18,2)")]
public decimal FinalPrice { get; set; }
[Column("used_money", TypeName = "decimal(18,2)")]
public decimal UsedMoney { get; set; } = 0;
[Column("used_integral", TypeName = "decimal(18,2)")]
public decimal UsedIntegral { get; set; } = 0;
[Column("used_money2", TypeName = "decimal(18,2)")]
public decimal UsedMoney2 { get; set; } = 0;
[Column("coupon_id")]
public int? CouponId { get; set; }
[Column("used_coupon", TypeName = "decimal(18,2)")]
public decimal UsedCoupon { get; set; } = 0;
[Column("draw_count")]
public int DrawCount { get; set; } = 0;
[Column("pay_type")]
public byte PayType { get; set; } = 1;
[Column("status")]
public byte Status { get; set; } = 0;
[Column("click_id")]
public int? ClickId { get; set; }
[Column("created_at")]
public DateTime CreatedAt { get; set; } = DateTime.Now;
[Column("paid_at")]
public DateTime? PaidAt { get; set; }
// 导航属性
[ForeignKey("UserId")]
public virtual User User { get; set; } = null!;
[ForeignKey("GoodsId")]
public virtual Goods Goods { get; set; } = null!;
public virtual ICollection<OrderItem> Items { get; set; } = new List<OrderItem>();
}
}
4.3 实体配置类 (0.2天)
任务描述
创建Fluent API配置类,精确控制实体映射
具体工作
- 创建实体配置类
- 配置索引和约束
- 设置外键关系
- 配置查询过滤器
实体配置
1. 用户配置
// Configurations/UserConfiguration.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using HoneyBox.Core.Entities;
namespace HoneyBox.Data.Configurations
{
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("users");
// 主键
builder.HasKey(e => e.Id);
builder.Property(e => e.Id).ValueGeneratedOnAdd();
// 唯一索引
builder.HasIndex(e => e.OpenId).IsUnique().HasDatabaseName("ix_users_open_id");
builder.HasIndex(e => e.Uid).IsUnique().HasDatabaseName("ix_users_uid");
// 普通索引
builder.HasIndex(e => e.Mobile).HasDatabaseName("ix_users_mobile");
builder.HasIndex(e => e.UnionId).HasDatabaseName("ix_users_union_id");
builder.HasIndex(e => new { e.Status, e.CreatedAt }).HasDatabaseName("ix_users_status_created");
builder.HasIndex(e => e.ParentId).HasDatabaseName("ix_users_parent_id");
// 字段配置
builder.Property(e => e.OpenId).IsRequired().HasMaxLength(50);
builder.Property(e => e.UnionId).HasMaxLength(255);
builder.Property(e => e.GzhOpenId).HasMaxLength(255);
builder.Property(e => e.Mobile).HasMaxLength(15);
builder.Property(e => e.Nickname).IsRequired().HasMaxLength(255);
builder.Property(e => e.HeadImg).IsRequired().HasMaxLength(500);
builder.Property(e => e.Uid).IsRequired().HasMaxLength(16);
// 默认值
builder.Property(e => e.ParentId).HasDefaultValue(0);
builder.Property(e => e.Money).HasDefaultValue(0).HasColumnType("decimal(18,2)");
builder.Property(e => e.Money2).HasDefaultValue(0).HasColumnType("decimal(18,2)");
builder.Property(e => e.Integral).HasDefaultValue(0).HasColumnType("decimal(18,2)");
builder.Property(e => e.Score).HasDefaultValue(0).HasColumnType("decimal(18,2)");
builder.Property(e => e.OuQi).HasDefaultValue(0);
builder.Property(e => e.OuQiLevel).HasDefaultValue(0);
builder.Property(e => e.VipLevel).HasDefaultValue((byte)1);
builder.Property(e => e.Status).HasDefaultValue((byte)1);
builder.Property(e => e.IsTest).HasDefaultValue(0);
builder.Property(e => e.CreatedAt).HasDefaultValueSql("GETDATE()");
builder.Property(e => e.UpdatedAt).HasDefaultValueSql("GETDATE()");
// 导航属性
builder.HasOne(e => e.Account)
.WithOne(a => a.User)
.HasForeignKey<UserAccount>(a => a.UserId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasMany(e => e.Orders)
.WithOne(o => o.User)
.HasForeignKey(o => o.UserId)
.OnDelete(DeleteBehavior.Restrict);
}
}
}
2. 商品配置
// Configurations/GoodsConfiguration.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using HoneyBox.Core.Entities;
namespace HoneyBox.Data.Configurations
{
public class GoodsConfiguration : IEntityTypeConfiguration<Goods>
{
public void Configure(EntityTypeBuilder<Goods> builder)
{
builder.ToTable("goods");
// 主键
builder.HasKey(e => e.Id);
builder.Property(e => e.Id).ValueGeneratedOnAdd();
// 索引
builder.HasIndex(e => new { e.Type, e.Status }).HasDatabaseName("ix_goods_type_status");
builder.HasIndex(e => new { e.Status, e.SortOrder }).HasDatabaseName("ix_goods_status_sort");
builder.HasIndex(e => e.CategoryId).HasDatabaseName("ix_goods_category_id");
builder.HasIndex(e => e.CreatedAt).HasDatabaseName("ix_goods_created_at");
builder.HasIndex(e => e.UnlockAmount).HasDatabaseName("ix_goods_unlock_amount");
// 字段配置
builder.Property(e => e.Title).IsRequired().HasMaxLength(255);
builder.Property(e => e.ImgUrl).IsRequired().HasMaxLength(500);
builder.Property(e => e.ImgUrlDetail).IsRequired().HasMaxLength(500);
// 默认值
builder.Property(e => e.CategoryId).HasDefaultValue(0);
builder.Property(e => e.Price).HasDefaultValue(0).HasColumnType("decimal(18,2)");
builder.Property(e => e.Stock).HasDefaultValue(0);
builder.Property(e => e.SaleStock).HasDefaultValue(0);
builder.Property(e => e.Type).HasDefaultValue((byte)0);
builder.Property(e => e.Status).HasDefaultValue((byte)1);
builder.Property(e => e.IsLock).HasDefaultValue((byte)0);
builder.Property(e => e.LockTime).HasDefaultValue(0);
builder.Property(e => e.IsDiscount).HasDefaultValue((byte)0);
builder.Property(e => e.IsNew).HasDefaultValue((byte)0);
builder.Property(e => e.IsShow).HasDefaultValue((byte)0);
builder.Property(e => e.UnlockAmount).HasDefaultValue(0).HasColumnType("decimal(18,2)");
builder.Property(e => e.DailyLimit).HasDefaultValue(0);
builder.Property(e => e.GlobalLimit).HasDefaultValue(0);
builder.Property(e => e.SortOrder).HasDefaultValue(1);
builder.Property(e => e.CreatedAt).HasDefaultValueSql("GETDATE()");
builder.Property(e => e.UpdatedAt).HasDefaultValueSql("GETDATE()");
// 软删除查询过滤器
builder.HasQueryFilter(e => e.DeletedAt == null);
// 导航属性
builder.HasMany(e => e.Items)
.WithOne(i => i.Goods)
.HasForeignKey(i => i.GoodsId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(e => e.Extension)
.WithOne(ext => ext.Goods)
.HasForeignKey<GoodsExtension>(ext => ext.GoodsId)
.OnDelete(DeleteBehavior.Cascade);
}
}
}
4.4 API接口适配 (0.1天)
任务描述
更新API控制器以使用新的EF Core上下文
具体工作
- 更新控制器依赖注入
- 修改数据访问代码
- 适配查询语法
- 测试API接口
API适配示例
1. 用户控制器适配
// Controllers/UserController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using HoneyBox.Data;
using HoneyBox.Core.Entities;
namespace HoneyBox.Api.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly HoneyBoxDbContext _context;
private readonly ILogger<UserController> _logger;
public UserController(HoneyBoxDbContext context, ILogger<UserController> logger)
{
_context = context;
_logger = logger;
}
[HttpGet("{openId}")]
public async Task<ActionResult<User>> GetUser(string openId)
{
var user = await _context.Users
.Include(u => u.Account)
.FirstOrDefaultAsync(u => u.OpenId == openId);
if (user == null)
{
return NotFound();
}
return user;
}
[HttpPost("login")]
public async Task<ActionResult<User>> Login([FromBody] LoginRequest request)
{
var user = await _context.Users
.FirstOrDefaultAsync(u => u.OpenId == request.OpenId);
if (user == null)
{
// 创建新用户
user = new User
{
OpenId = request.OpenId,
UnionId = request.UnionId,
Nickname = request.Nickname,
HeadImg = request.HeadImg,
Uid = GenerateUid(),
CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now
};
_context.Users.Add(user);
await _context.SaveChangesAsync();
}
else
{
// 更新用户信息
user.Nickname = request.Nickname;
user.HeadImg = request.HeadImg;
user.LastLoginAt = DateTime.Now;
user.UpdatedAt = DateTime.Now;
await _context.SaveChangesAsync();
}
return user;
}
[HttpGet("{userId}/balance")]
public async Task<ActionResult<object>> GetBalance(int userId)
{
var user = await _context.Users
.Where(u => u.Id == userId)
.Select(u => new
{
u.Money,
u.Money2,
u.Integral,
u.Score
})
.FirstOrDefaultAsync();
if (user == null)
{
return NotFound();
}
return user;
}
private string GenerateUid()
{
return "U" + DateTime.Now.ToString("yyyyMMddHHmmss") + Random.Shared.Next(1000, 9999);
}
}
public class LoginRequest
{
public string OpenId { get; set; } = string.Empty;
public string? UnionId { get; set; }
public string Nickname { get; set; } = string.Empty;
public string HeadImg { get; set; } = string.Empty;
}
}
2. 商品控制器适配
// Controllers/GoodsController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using HoneyBox.Data;
using HoneyBox.Core.Entities;
namespace HoneyBox.Api.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class GoodsController : ControllerBase
{
private readonly HoneyBoxDbContext _context;
public GoodsController(HoneyBoxDbContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Goods>>> GetGoods(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
[FromQuery] byte? type = null)
{
var query = _context.Goods
.Where(g => g.Status == 1 && g.IsShow == 1);
if (type.HasValue)
{
query = query.Where(g => g.Type == type.Value);
}
var goods = await query
.OrderByDescending(g => g.SortOrder)
.ThenByDescending(g => g.CreatedAt)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return goods;
}
[HttpGet("{id}")]
public async Task<ActionResult<Goods>> GetGoods(int id)
{
var goods = await _context.Goods
.Include(g => g.Items.Where(i => i.SurplusStock > 0))
.Include(g => g.Extension)
.FirstOrDefaultAsync(g => g.Id == id);
if (goods == null)
{
return NotFound();
}
return goods;
}
[HttpGet("{id}/items")]
public async Task<ActionResult<IEnumerable<GoodsItem>>> GetGoodsItems(int id, int boxNumber)
{
var items = await _context.GoodsItems
.Where(i => i.GoodsId == id && i.BoxNumber == boxNumber)
.OrderBy(i => i.SortOrder)
.ToListAsync();
return items;
}
}
}
验收标准
配置验收
- EF Core 8.0包安装成功
- 连接字符串配置正确
- DbContext创建并注册成功
- 依赖注入配置完成
实体模型验收
- 所有实体类创建完成
- 实体配置类配置正确
- 导航属性设置完成
- 索引和约束配置正确
API适配验收
- 控制器依赖注入更新完成
- 数据访问代码适配完成
- API接口测试通过
- 查询性能满足要求
风险点和注意事项
配置风险
- 连接字符串错误: 可能导致连接失败
- EF Core版本兼容性: 确保版本匹配
- 依赖注入配置: 生命周期管理要正确
- 数据库权限: 确保应用程序有足够权限
实体映射风险
- 字段映射错误: 可能导致数据读取失败
- 数据类型不匹配: 精度丢失或溢出
- 导航属性循环引用: 序列化问题
- 查询过滤器: 可能影响预期查询结果
解决方案
- 分步测试: 每个组件完成后立即测试
- 日志记录: 详细记录EF Core查询日志
- 单元测试: 为关键功能编写单元测试
- 性能监控: 监控查询性能和数据库连接
下一阶段准备
为阶段5准备的内容
- 功能测试用例
- 性能基准测试
- 压力测试工具
- 监控指标配置
交接文档
- EF Core配置文档
- 实体模型设计文档
- API适配说明
- 测试验证报告
阶段4完成标志: EF Core 8.0配置完成,实体模型创建成功,API接口适配完成,应用程序可以正常连接和操作SQL Server数据库。