【问题标题】:Entity Framework DbContext is trying to insert data, that already exists实体框架 DbContext 正在尝试插入已经存在的数据
【发布时间】:2019-09-16 23:48:09
【问题描述】:

我有两个DbContext 课程。 ServerContext 具有 UserContext 的外键。

服务器上下文:

public ServerContext(DbContextOptions<ServerContext> options)
  : base(options) {
}

public DbSet<Server> Server { get; set; }

protected override void OnModelCreating(ModelBuilder builder) 
{
    base.OnModelCreating(builder);
    builder.Entity<Server>().ToTable("Server");

    builder.Entity<User.User>().HasMany(x => x.Servers).WithOne(x => x.User);
}

服务器:

public class Server 
{
    public string ServerId { get; set; }

    [Required]
    [InverseProperty("User")]
    public string UserId { get; set; }
    public virtual User.User User { get; set; }
}

用户上下文:

public class UserContext : IdentityDbContext<User> 
{
    public UserContext(DbContextOptions<UserContext> options)
      : base(options) 
    {
    }

    public DbSet<User> User { get; set; }

    protected override void OnModelCreating(ModelBuilder builder) 
    {
        base.OnModelCreating(builder);
        builder.Entity<User>().ToTable("User");
    }
}

用户:

public class User : IdentityUser 
{
    public virtual ICollection<Server.Server> Servers { get; set; }
}

在启动时,我将所有 Server 数据提取到缓存中并每分钟更新一次。

错误发生在模型中。在我使用服务器数据的模型上。 之后,我正在检查服务器数据是否包含非空用户数据。 是否为空,我是从数据库中加载(这一步抛出错误)。

public async Task OnGetAsync() 
{
    Servers = await this.ServerManager.GetServersAsync();

    foreach (var server in Servers) 
    {
        if(server == null) 
            continue;

        // This code triggers the error
        var user = await UserManager.FindByIdAsync(server.UserId);

        if(user == null) 
           continue;

        server.User = user;
    }
}

用户:

  public class User : IdentityUser {

    public virtual ICollection<IdentityRole> Roles { get; set; }

    public virtual ICollection<Server.Server> Servers { get; set; }
  }

6 次查询一个用户数据: https://pastebin.com/ud9eeKKe

每分钟我都会保存数据,但我收到以下错误:

DbUpdateException:更新条目时出错。 有关详细信息,请参阅内部异常。 MySql.Data.MySqlClient.MySqlException: 键“P​​RIMARY”的重复条目“2f2469d5-b35e-42d8-a90c-a6cc3b899b5a”MySql.Data.MySqlClient.MySqlException:键“PRIMARY”的重复条目“2f2469d5-b35e-42d8-a90c-a6cc3b899b5a”。

【问题讨论】:

  • 能不能改一下ServerManager.GetServersAsync()的代码?
  • 是的,我可以做到。这是自定义管理器。
  • 然后您可以将用户包含在服务器中并删除导致错误的代码。
  • 但我不想从数据库中获取所有数据。性能原因。
  • 所有数据是什么?与其他用户不同的身份用户?

标签: asp.net asp.net-core .net-core entity-framework-core


【解决方案1】:

正如您所提到的,您可以更改 GetServersAsync 方法的代码,我希望 DbContext-Call 看起来类似于:

return ServerContext.Servers;

你可以改成:

return ServerContext.Servers.Include(u=>u.User);

这样,您可以跳过导致外部代码的错误,因为用户已经被填充。​​

错误确实发生了,因为您将 User-Property 设置为被跟踪的实体。

或者,您可以在保存之前将 User-Property 设置为空。 或者您可以在将 User 设置为 User-Property 之前将 User as EntityEntry 设置为未更改(出于性能问题,我不建议这样做)。

作为另一种选择,您可以集成延迟加载,它是在 EF Core 2.1 中引入的,如 here 所述。

更新:

您可以加载您的服务器 NotTracked 以防止保存问题:

return ServerContext.Servers.AsNoTracking();

然后你可以添加用户,就像你已经做的那样...... 稍后,在保存服务器之前,您必须执行以下步骤:

  1. 再次将 User 设为 null

  2. 将已更新的服务器对象添加到上下文中

  3. 调用 SaveChanges

【讨论】:

  • 差不多,我在后面使用缓存系统。问题是:例如,我每分钟从数据库中获取 10.000 个对象,包括用户(包括 userdetails、usersettings、....),但我从不需要带有用户数据的 10.000 个对象。不必要的负载。
  • @TimoFalter 那么您如何过滤,您需要哪些服务器/用户?
  • 在我看来,我加载的前 25 个对象包括用户。在后台即时刷新所有服务器对象。
  • @TimoFalter 那么你更喜欢什么?延迟加载还是 Context.Entry?我认为两者都可以满足您的需求。
  • @TimoFalter 是否应该通过 Savechanges 更新用户?否则还有其他办法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 2018-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-17
相关资源
最近更新 更多