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

.NET7 MongoDB EF插入赛事时UserId为空ObjectId问题排查

问题:MongoDB EF Core插入赛事时UserId存储为空ObjectId

我使用C# .NET7结合MongoDB Entity Framework开发国际象棋赛事WebAPI,遇到一个问题:插入关联用户的赛事时,MongoDB中的UserId字段总是被存储为ObjectId('000000000000000000000000'),而非实际的用户ID。

我的Tournament模型定义了ObjectId?类型的UserId字段,服务层与控制器实现了赛事添加逻辑,前端TypeScript脚本获取用户ID后组装赛事数据发起POST请求,日志显示userId已正确赋值,但数据库中仍为空ObjectId,寻求解决建议。


相关代码

TournamentModel.cs

public enum TournamentStatus
{
    Planned,
    Ongoing,
    Finished,
}
public enum TournamentType
{
    Classic,
    Rapid,
    Blitz,
    Bullet
}
[Collection("tournaments")]
public class Tournament
{
    public ObjectId Id { get; set; }
    public ObjectId? UserId { get; set; }
    [Required(ErrorMessage ="Title is required")]
    public string Title { get; set; }        
    public string EventUrl { get; set; }        
    public string County { get; set; }
    [Required(ErrorMessage = "Status is required")]
    public TournamentStatus Status { get; set; }


    [Required(ErrorMessage ="Provide type of tournament")]
    public TournamentType Type {  get; set; }
    [Required(ErrorMessage = "Provide information whether the tournament is FIDE classified")]
    public Boolean IsFide {  get; set; }
    [Required(ErrorMessage ="Provide details for tournament")]
    public TournamentDetails Details { get; set; }        
}

TournamentService.cs 添加逻辑

public void AddTournament(Tournament newTournament)
{                        
    _BCAContextDb.Tournaments.Add(newTournament);
    _BCAContextDb.ChangeTracker.DetectChanges();
    Console.WriteLine(_BCAContextDb.ChangeTracker.DebugView.LongView);
    _BCAContextDb.SaveChanges();
}

TournamentController.cs POST逻辑

[HttpPost]
public ActionResult<Tournament> PostTournament(Tournament tournament)
{            
    _tournamentService.AddTournament(tournament);
    return CreatedAtAction(nameof(GetTournamentById), new { id = tournament.Id }, tournament);
}

前端TypeScript脚本

const agent = new https.Agent({
  rejectUnauthorized: false,
});

let tournament = {
  userId:{},
  title: "string",
  eventUrl: "string",
  county: "string",
  status: 0,
  type: 0,
  isFide: true,
  details: {
    startDate: "2024-03-13T18:53:41.465Z",
    endDate: "2024-03-13T18:53:41.465Z",
    place: "string",
    gameTempo: "string",
    referee: "string",
    organizer: "string",
    roundsTotal: 0,
    roundsEnded: 0,
    gameSystem: "string",
  },
};

const grabData = async () => {
  try {
    const response = await axios.get("https://localhost:7001/api/user", { httpsAgent: agent });
    const id = response.data[0].id;
    
    console.log(id);
    return id;
  } catch (error) {
    console.error("Error:", error.message);
    throw error;
  }
};

const main = async () => {
  try {
    const userId = await grabData();
    tournament.userId = userId;
    const tournamentToPush = tournament;
    console.log("Tournament pushed:", tournamentToPush);
    const response = await axios.post("https://localhost:7001/api/tournament", tournamentToPush, { httpsAgent: agent });
    console.log("Tournament created:", response.data);
  } catch (error) {
    console.error("Error:", error.message);
  }
};

main();

解决建议

  • 修复ObjectId与字符串的序列化映射
    前端传递的用户ID是字符串格式,后端ObjectId类型无法自动解析,导致被初始化为空ObjectId。在模型的UserId字段添加特性,让MongoDB EF Core自动处理字符串到ObjectId的转换:

    [BsonRepresentation(BsonType.ObjectId)]
    public ObjectId? UserId { get; set; }
    
  • 修正前端数据初始格式
    前端初始定义tournament.userId为{},可能导致序列化异常。改为字符串类型:

    let tournament = {
      userId: "", // 替换原空对象
      // ...其他字段
    };
    
  • 使用DTO接收前端数据(推荐)
    避免直接用实体类处理序列化,新增DTO类接收字符串ID,手动转换为ObjectId:

    // 新增DTO
    public class TournamentDto
    {
        public string UserId { get; set; }
        // 复制Tournament类的其他字段
    }
    
    // 修改控制器逻辑
    [HttpPost]
    public ActionResult<Tournament> PostTournament([FromBody] TournamentDto tournamentDto)
    {
        var tournament = new Tournament
        {
            UserId = ObjectId.TryParse(tournamentDto.UserId, out var objId) ? objId : null,
            Title = tournamentDto.Title,
            Status = tournamentDto.Status,
            // 映射其他字段
        };
        _tournamentService.AddTournament(tournament);
        return CreatedAtAction(nameof(GetTournamentById), new { id = tournament.Id }, tournament);
    }
    
  • 验证ChangeTracker日志细节
    仔细查看ChangeTracker.DebugView.LongView的输出,确认UserId的实际值是否为有效ObjectId。如果日志中显示为字符串,说明序列化未完成转换,需优先处理序列化配置。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:27:04