You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# EF Core 实体属性未映射生成数据库列的问题咨询

问题产生原因

列未生成是三个核心问题导致的:

  • EF Core默认映射规则只识别带公开get、set访问器的可读写属性,你写的PlayerX、PlayerO、Mode、Winner、Loser、Status全是只有get的计算属性,没有setter,EF Core默认把这些属性归为运行时计算的临时逻辑,不纳入持久化范围,自然不会生成对应列。
  • 声明Mode和Status属性时,返回值用的是基类Enum,不是代码里定义的具体枚举类型GameMode、GameStatus,EF Core无法识别这个通用基类该怎么映射成数据库字段,就算加了setter也会映射失败。
  • 现有GameScores实体设计本身不符合EF使用规范:实体是纯数据载体,你在内部直接new了MainWindowViewModel,还依赖运行时的CurrentGame状态计算属性值,后续从数据库读取历史记录时,这些属性找不到对应的游戏实例,会直接抛出空引用错误,根本无法正常使用。
修复方案

按以下步骤修改即可:

  1. 先把GameScores重构为纯数据模型,删掉所有对ViewModel、游戏逻辑类的依赖,所有需要存库的属性都加上setter,枚举属性使用具体的枚举类型,不要用Enum基类:
public class GameScores
{
    // 主键为数据库自增字段,不需要声明为nullable
    public int GameScoreId { get; set; }
    public string PlayerX { get; set; } = string.Empty;
    public string PlayerO { get; set; } = string.Empty;
    // 用具体枚举类型代替Enum基类
    public GameMode Mode { get; set; }
    public string? Winner { get; set; }
    public string? Loser { get; set; }
    // 用具体枚举类型代替Enum基类
    public GameStatus Status { get; set; }
}
  1. 原来写在实体里的属性计算逻辑,挪到游戏结束触发保存的业务代码位置(也就是MainWindowViewModel里处理游戏结束的方法中),手动给GameScores对象赋值后再存入数据库,参考代码:
// 游戏结束判定通过后,调用该方法存储对局记录
private void SaveGameResult()
{
    if (CurrentGame == null || !CurrentGame.GameOver) return;

    var record = new GameScores
    {
        PlayerX = CurrentGame.PlayerX.Name,
        PlayerO = CurrentGame.PlayerO.Name,
        Mode = CurrentGame.PlayerO switch
        {
            HumanPlayer => GameMode.HumanVsHuman,
            EasyCom => GameMode.HumanVsEasyBot,
            HardCom => GameMode.HumanVsHardBot,
            _ => throw new NotImplementedException()
        },
        Winner = CurrentGame.GetFreeFields().Count != 0 ? CurrentGame.CurrentPlayer!.Name : null,
        Loser = CurrentGame.GetFreeFields().Count != 0 ? CurrentGame.CurrentPlayer!.Enemy!.Name : null,
        Status = CurrentGame.GetFreeFields().Count != 0 ? GameStatus.Win : GameStatus.Draw
    };

    using var db = new GameScoresContext();
    db.GameScores!.Add(record);
    db.SaveChanges();
}
  1. (可选配置)如果想让数据库存储枚举的字符串值而不是数字,避免后续调整枚举顺序导致历史数据错乱,可以在DbContext的OnModelCreating方法中添加转换配置:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<GameScores>().HasKey(e => e.GameScoreId);
    // 配置枚举转换为字符串存储
    modelBuilder.Entity<GameScores>().Property(e => e.Mode).HasConversion<string>();
    modelBuilder.Entity<GameScores>().Property(e => e.Status).HasConversion<string>();
}
  1. 删掉之前生成的错误迁移文件夹,重新在NuGet包管理器控制台执行两条命令:
  • Add-Migration FixGameScoreTableColumns
  • Update-Database

注意:EF实体类不要耦合任何UI、业务逻辑依赖,它的作用只是和数据库表做字段映射,所有字段值的计算、赋值都要在业务层完成,否则会出现各种映射失败、运行时报错的问题。

内容的提问来源于stack exchange,提问作者44ay_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 15:15:34