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

EF Core 8创建Room时误创关联Player引发MySQL报错求助

问题描述

使用EF Core 8创建Room实体时出现以下错误:

Microsoft.EntityFrameworkCore.DbUpdateException: 保存实体变更时发生错误,请查看内部异常详情。
MySqlConnector.MySqlException (0x80004005): Field 'password' doesn't have a default value

经排查,问题出在Room关联Player实体时,EF Core自动尝试创建新的Player记录,但实际需求是仅创建Room并关联已存在的Player,而非新建Player。

执行的SQL语句

INSERT INTO `players` (`id`, `created_at`, `email`, `username`)
VALUES (@p0, @p1, @p2, @p3);
INSERT INTO `player_avatar_data` (`id`, `chat_bubble_id`, `figure_code`, `gender`, `motto`, `player_id`)
VALUES (@p4, @p5, @p6, @p7, @p8, @p9);
INSERT INTO `player_data` (`id`, `achievement_score`, `allow_friend_requests`, `credit_balance`, `gotw_points`, `home_room_id`, `is_online`, `last_online`, `pixel_balance`, `player_id`, `respect_points`, `respect_points_pet`, `seasonal_balance`)
VALUES (@p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21, @p22);
INSERT INTO `player_game_settings` (`id`, `block_camera_follow`, `block_room_invites`, `furniture_volume`, `player_id`, `prefer_old_chat`, `show_notifications`, `system_volume`, `trax_volume`, `ui_flags`)
VALUES (@p23, @p24, @p25, @p26, @p27, @p28, @p29, @p30, @p31, @p32);
INSERT INTO `player_navigator_settings` (`id`, `open_searches`, `player_id`, `window_height`, `window_width`, `window_x`, `window_y`)
VALUES (@p33, @p34, @p35, @p36, @p37, @p38, @p39);
INSERT INTO `rooms` (`created_at`, `description`, `is_muted`, `layout_id`, `max_users_allowed`, `name`, `owner_id`)
VALUES (@p40, @p41, @p42, @p43, @p44, @p45, @p46);
SELECT `id`
FROM `rooms`
WHERE ROW_COUNT() = 1 AND `id` = 449989;

INSERT INTO `rooms` (`id`, `created_at`, `description`, `is_muted`, `layout_id`, `max_users_allowed`, `name`, `owner_id`)
VALUES (@p47, @p48, @p49, @p50, @p51, @p52, @p53, @p54),
(@p55, @p56, @p57, @p58, @p59, @p60, @p61, @p62);
INSERT INTO `room_settings` (`id`, `access_type`, `allow_pets`, `can_pets_eat`, `can_users_overlap`, `floor_thickness`, `hide_walls`, `password`, `room_id`, `trade_option`, `walk_diagonal`, `wall_thickness`, `who_can_ban`, `who_can_kick`, `who_can_mute`)
VALUES (@p63, @p64, @p65, @p66, @p67, @p68, @p69, @p70, @p71, @p72, @p73, @p74, @p75, @p76, @p77),
(@p78, @p79, @p80, @p81, @p82, @p83, @p84, @p85, @p86, @p87, @p88, @p89, @p90, @p91, @p92);

Room实体定义

public class Room
{
    public int Id { get; init; }
    public string? Name { get; set; }
    public int LayoutId { get; init; }
    public RoomLayout? Layout { get; init; }
    public int OwnerId { get; init; }
    public Player? Owner { get; init; }
    public int MaxUsersAllowed { get; set; }
    public string? Description { get; set; }
    public bool IsMuted { get; init; }
    public RoomSettings? Settings { get; set; }
    public RoomPaintSettings? PaintSettings { get; set; }
    public RoomChatSettings? ChatSettings { get; set; }
    public DateTime CreatedAt { get; init; }
}

创建Room的代码

var newRoom = new Room
{
    Name = eventParser.Name,
    LayoutId = layout.Id,
    Layout = layout,
    OwnerId = client.Player.Id,
    Owner = client.Player,
    MaxUsersAllowed = 50,
    Description = eventParser.Description,
    CreatedAt = DateTime.Now
};

newRoom.Settings = new RoomSettings
{
    RoomId = newRoom.Id,
    Password = ""
};

newRoom.ChatSettings = new RoomChatSettings
{
    RoomId = newRoom.Id
};

newRoom.PaintSettings = new RoomPaintSettings
{
    RoomId = newRoom.Id,
};

dbContext.Rooms.Add(newRoom);
roomRepository.AddRoom(newRoom);
client.Player.Rooms.Add(newRoom);

await dbContext.SaveChangesAsync();
解决方案

可以通过以下几种方式实现创建Room时仅关联已存在的Player,避免EF Core自动新建Player:

1. 仅设置外键ID,不赋值导航属性

EF Core会自动通过外键OwnerId关联已存在的Player,无需赋值Owner导航属性。修改创建Room的代码:

var newRoom = new Room
{
    Name = eventParser.Name,
    LayoutId = layout.Id,
    Layout = layout,
    OwnerId = client.Player.Id, // 只保留外键ID
    // 移除 Owner = client.Player;
    MaxUsersAllowed = 50,
    Description = eventParser.Description,
    CreatedAt = DateTime.Now
};

2. 将Player实体附加到上下文(标记为已存在)

如果必须保留Owner导航属性的赋值,需要将client.Player附加到当前DbContext,告知EF Core该实体已存在于数据库中,无需创建新记录:

// 在创建Room前执行
dbContext.Attach(client.Player);

var newRoom = new Room
{
    // ... 其他属性
    OwnerId = client.Player.Id,
    Owner = client.Player
};

// ... 后续代码不变

3. 配置EF Core关系为无外键级联创建

在DbContext的OnModelCreating方法中,显式配置Room与Player的关系,设置不级联创建关联实体:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Room>()
        .HasOne(r => r.Owner)
        .WithMany(p => p.Rooms) // 假设Player有Rooms集合导航属性
        .HasForeignKey(r => r.OwnerId)
        .OnDelete(DeleteBehavior.Restrict) // 可选,根据需求设置删除行为
        .IsRequired()
        .WillCascadeOnDelete(false); // 禁用级联创建
}

4. 检查Repository的AddRoom方法

确保roomRepository.AddRoom方法没有额外将Owner标记为需要新增的实体,避免干扰EF Core的实体跟踪状态。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:29:49