EF Core 6下ASP.NET只读库无外键时如何显示状态名称
解决方案
1. 定义实体类并配置无外键关联
先为参考表和业务表创建实体类,再通过EF Core的Fluent API手动配置关联关系(无需数据库存在物理外键):
参考表实体
public class StatusReference { public int StatusCode { get; set; } public string StatusName { get; set; } }
业务表实体(以订单表为例)
public class Order { public int Id { get; set; } public int OrderStatus { get; set; } // 状态编码字段 // 其他业务字段... // 导航属性,用于关联状态名称 public StatusReference Status { get; set; } }
在DbContext中配置关联
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置参考表主键 modelBuilder.Entity<StatusReference>() .HasKey(s => s.StatusCode); // 配置订单表与状态参考表的关联(无数据库外键约束) modelBuilder.Entity<Order>() .HasOne<StatusReference>(o => o.Status) .WithMany() .HasForeignKey(o => o.OrderStatus) .IsRequired(false); // 允许状态为空的场景可保留,否则改为IsRequired() // 其他业务表(如Invoice)同理配置关联 modelBuilder.Entity<Invoice>() .HasOne<StatusReference>(i => i.Status) .WithMany() .HasForeignKey(i => i.InvoiceStatus) .IsRequired(false); }
2. 查询时投影到视图模型
通过视图模型封装展示数据,避免实体与视图结构不匹配的问题:
创建视图模型
public class OrderViewModel { public int Id { get; set; } public string OrderStatusName { get; set; } // 其他需要展示的业务字段... }
两种查询关联方式
- 方式1:通过导航属性Include关联
var orders = await _context.Orders .Include(o => o.Status) .Select(o => new OrderViewModel { Id = o.Id, OrderStatusName = o.Status?.StatusName ?? "未知状态", // 映射其他字段 }) .ToListAsync();
- 方式2:直接Join查询(无需配置导航属性)
var orders = await _context.Orders .Join(_context.StatusReferences, o => o.OrderStatus, s => s.StatusCode, (o, s) => new OrderViewModel { Id = o.Id, OrderStatusName = s.StatusName, // 映射其他字段 }) .ToListAsync();
3. 缓存状态参考数据优化性能
由于数据库只读,状态编码与名称的映射关系基本不会变化,可缓存参考表数据减少数据库查询:
注册缓存服务(Program.cs/.NET 6+)
builder.Services.AddMemoryCache();
在业务服务中使用缓存
private readonly IMemoryCache _cache; private readonly AppDbContext _context; public OrderService(IMemoryCache cache, AppDbContext context) { _cache = cache; _context = context; } // 获取缓存的状态映射字典 private async Task<Dictionary<int, string>> GetStatusCacheAsync() { return await _cache.GetOrCreateAsync("StatusCache", async entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(7); // 缓存7天,可按需调整 var statuses = await _context.StatusReferences.ToListAsync(); return statuses.ToDictionary(s => s.StatusCode, s => s.StatusName); }); } // 查询订单并映射状态名称 public async Task<List<OrderViewModel>> GetOrdersAsync() { var statusDict = await GetStatusCacheAsync(); var orders = await _context.Orders .Select(o => new OrderViewModel { Id = o.Id, OrderStatusName = statusDict.TryGetValue(o.OrderStatus, out var name) ? name : "未知状态", // 映射其他字段 }) .ToListAsync(); return orders; }
4. 视图中展示状态名称
在Razor视图中直接绑定视图模型的状态名称字段:
@model List<OrderViewModel> <table> <thead> <tr> <th>订单ID</th> <th>订单状态</th> <!-- 其他表头 --> </tr> </thead> <tbody> @foreach (var order in Model) { <tr> <td>@order.Id</td> <td>@order.OrderStatusName</td> <!-- 其他单元格 --> </tr> } </tbody> </table>
内容的提问来源于stack exchange,提问作者ScribKid
相关产品推荐
相关产品推荐

