如何在已登录用户的情况下添加新用户?

3

我在从头创建新用户(注册)和从已登录的用户中创建新用户时遇到了一种奇怪的行为,它不依赖于底层的数据库(在这种情况下,我使用的是postgreSQL)。

但首先,这里是它们之间的关系:

Tables relationships

现在,在注册和登录时,我都使用UserManager来创建用户。

首先,我创建一个新的UserSetting,进行SaveChanges(),然后将新创建实体的Id值分配给AppUser属性UserSettingId

这就是它失败的地方,具体取决于您是否已注册并登录的用户或者是新注册的用户,代码没有改变:

var userSettings = await _userService.UserSettings.AddAsync(new UserSettings
{
    LanguageId = langId,
    ThemeId = themeId
});
//wrapper to the Context.SaveChangesAsync()
//failure point!
if (!await _userService.SaveChangesAsync<bool>())

在创建一个已登录用户的新用户时,异常错误(exception error)提到了一个PK_LanguageId已经存在,就好像我正在创建一个新的Language实体,但是,正如您所看到的,我只是将默认的langId分配给了新的UserSetting。以下是异常截图:enter image description here 简短翻译:在Languages中出现了重复键,就好像它还试图插入一个新的Language实体。
Startup中注册的服务(_userService)是瞬态的。
以下是模型类及其在OnModelCreating中的配置:
public class AppUser : IdentityUser
{
    public long UserSettingsId { get; set; }
    public virtual UserSettings UserSettings { get; set; }
    //...other properties
}
public class UserSettings
{
    public long Id { get; set; }

    public int LanguageId { get; set; }
    public virtual Language Language { get; set; }

    public int ThemeId { get; set; }
    public virtual Theme Theme { get; set; }

    public virtual AppUser AppUser { get; set; }
}
public class Theme
{
    [Key]
    public int Id { get; set; }
    [StringLength(10)]
    public string Type { get; set; }
}
public class Language
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    [MaxLength(2)]
    public string Code { get; set; }
}


builder.Entity<AppUser>().HasKey(u => u.Id);
builder.Entity<AppUser>().HasOne(u => u.UserSettings).WithOne(us => us.AppUser);

builder.Entity<UserSettings>().HasKey(us => us.Id);
builder.Entity<UserSettings>().Property(us => us.Id).ValueGeneratedOnAdd();
builder.Entity<UserSettings>().HasOne(us => us.Language);
builder.Entity<UserSettings>().HasOne(us => us.Theme);

我做错了什么?为什么它的行为如此不同?有没有从已登录用户创建用户的其他方法?

1
请问您能分享一下您的模型类吗? - Sergey Kudriavtsev
1
请提供异常信息。 - Zze
@Zze 提供了异常截图。 - Eugene
1
到目前为止,我在您提供的代码中没有发现任何问题。我唯一能想到的想法是,语言可能会错误地添加到了DBContext的不同位置。当您调用SaveChangesAsync时,您将保存上下文中已完成的所有更改,因此可能是这样。 - Sergey Kudriavtsev
@Sergey 再次检查,没有这样的地方,在哪里我可以添加语言。 - Eugene
2个回答

2

问题可能在于您正在将对象添加到数据库上下文中,从而将其标记为已添加。由于数据库上下文不知道存在 LanguageTheme 对象,因此它会尝试插入所有这些对象。

这可能是与 postgreSQL 提供程序有关的问题。您可能想要检查已打开的问题。

我建议先从数据库中加载 Language 对象,然后再尝试添加新的 UserSettings

注:Original Answer 翻译成“最初的回答”。


我尝试直接提供虚拟属性LanguageTheme,没有使用AsNoTracking(),结果出现了一些变化,现在异常是关于新的UserSettings具有与当前登录用户相同的设置Id!这到底是怎么回事... - Eugene
2
你能分享一下OnModelCreating方法吗?或者整个DbContext让我看看这个问题。谢谢。 - dropoutcoder

2
发现了行为的来源,就是该死的 UserManager.GetUserAsync(),我使用它来获取当前已登录用户,并在稍后添加UserSettings以将“管理员”的设置传播到新创建的帐户。 GetUserAsync(User)确实返回一个保持跟踪的实体(而不是像我想象的那样像AsNoTracking())。因此,当我填充它的UserSetting时,我实际上添加了一个具有新子类属性的新UserSetting
所以,永远不要指望UserManager在不跟踪的情况下向您提供用户!
感谢所有参与努力的人。

1
很高兴你找到了它!也许这篇文章将来会帮助到某个人。 - Sergey Kudriavtsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接