• WithOne 实体关系引起 EF Core 自动删除数据


    最近遇到了一个 EF Core 的恐怖问题,在添加数据时竟然会自动删除数据库中已存在的数据,经过追查发现是一个多余的实体关系配置引起的。

    modelBuilder.Entity<Question>()
        .HasOne(q => q.Owner)
        .WithOne();
    

    罪魁祸首就是上面的 WithOne()

    今天写了个非常简单的控制台程序重现了这个问题。

    实体类 Question 的定义

    public class Question
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public int UserId { get; set; }
        public User Owner { get; set; }
    }
    

    实体类 User 的定义

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    

    实体关系配置

    modelBuilder.Entity<Question>()
        .HasOne(q => q.Owner)
        .WithOne();
    

    触发问题的实体查询与添加代码

    class Program
    {
        static async Task Main(string[] args)
        {
            var conn = "server=.;database=question;integrated security=true";
    
            var host = new HostBuilder()
                .ConfigureServices(services =>
                {
                    services.AddDbContext<MyDbContext>(options => options.UseSqlServer(conn));
                }).Build();
    
            using (var db = host.Services.GetRequiredService<MyDbContext>())
            {
                var newQuestion = new Question
                {
                    Title = "test " + DateTime.Now.ToLongDateString(),
                    Owner = await db.Set<User>().FirstAsync(u => u.Id == 1)
                };
    
                var latestQuestion = await db.Set<Question>()
                    .Where(q => q.UserId == 1).OrderByDescending(q => q.Id).FirstOrDefaultAsync();
    
                db.Set<Question>().Add(newQuestion);
                await db.SaveChangesAsync();
            }
        }
    }
    

    EF Core 生成的在 INSERT 之前的 DELETE SQL 语句

    exec sp_executesql N'SET NOCOUNT ON;
    DELETE FROM [Question]
    WHERE [Id] = @p0;
    SELECT @@ROWCOUNT;
    

    问题分析(只是个人猜想)

    上面的代码中,创建一个新的 Question 实例时,与一个从数据库查询出来的 Id 为 1 的 User 实例进行了关联,此时这个 User 实例进入 EF Core 的跟踪范围,但这个新建的 Question 实例还没被 EF Core 跟踪。后来使用同样的 UserId 从数据库查询 Question ,查询出来的 Question 实例由于 WithOne 实体关系从而与已经被跟踪的 User 实例(因为 UserId 一样)进行了关联。此时被 EF Core 跟踪到的实体状态是:Id 为 1 的 User 实体与从数据库查询得到的 Id 为 x 的 Question 实体进行了一对一关联。而在 db.Set<Question>().Add(newQuestion) 时,EF Core 跟踪到了实体状态的变化 —— User 实体与一个没有 Id 的新 Question 实体关联了,对于这样的状态变化,EF Core 理所当然地做出了“正确的决定” —— 删除之前关联的 Question 实体,添加新的 Question 实体。

    解决方法

    去掉多条的 WithOne()

    示例代码

    重现这个问题的完整示例代码:https://github.com/cnblogs-dudu/efcore-unexpected-deletion

  • 相关阅读:
    Git中tag标签的使用
    antd vue Layout 组件收缩展开自定义
    antd vue Popover气泡卡片的使用
    antd vue Tree树形控件的使用
    antd vue Message 全局提示的使用
    tp5.1 关联条件查询haswhere 用field限制字段失效的问题
    Chrome 调试技巧: 调整网速
    html2canvas导出图片模糊
    点击其他区域不让编辑器失去焦点
    启动的项目经常挂怎么办
  • 原文地址:https://www.cnblogs.com/dudu/p/10616031.html
Copyright © 2020-2023  润新知