我有两个DbContext
类。 ServerContext
具有指向UserContext
的外键。
ServerContext:
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; }
}
UserContext:
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: 密钥'PRIMARY'MySql.Data.MySqlClient.MySqlException的条目'2f2469d5-b35e-42d8-a90c-a6cc3b899b5a'重复
答案 0 :(得分:1)
正如您提到的,您可以更改GetServersAsync方法的代码,我希望DbContext-Call看起来与此类似:
return ServerContext.Servers;
您可以将其更改为:
return ServerContext.Servers.Include(u=>u.User);
这样,您可以跳过导致代码外的错误,因为用户已被填充。
实际上发生了错误,因为您将用户属性设置为跟踪的实体。
或者,可以在保存之前将User-Property设置为null。 或者,您也可以在将用户设置为用户属性之前将用户设置为EntityEntry不变(对于性能问题,我不建议这样做)。
作为另一种选择,您可以集成延迟加载,该延迟加载是由here所述的EF Core 2.1引入的。
更新:
您可以加载未跟踪的服务器以防止保存问题:
return ServerContext.Servers.AsNoTracking();
然后,您可以添加用户,就像您已经做的那样... 稍后,在保存服务器之前,您必须执行以下步骤:
再次将用户设置为空
将服务器对象添加为已更新的上下文
调用SaveChanges