违反主键约束 ‘PK_Currencies’。无法在对象中插入重复的键。

huangapple go评论93阅读模式
英文:

Violation of PRIMARY KEY constraint 'PK_Currencies'. Cannot insert duplicate key in object

问题

我正在使用Blazor服务器开发项目。我有以下类结构用于我的项目。

我有三个类来处理这个错误。

ApplicationUser 类:

  1. public class ApplicationUser
  2. {
  3. public Guid ApplicationUserID { get; set; }
  4. [Required(ErrorMessage = "Name is required")]
  5. public string Name { get; set; } = null!;
  6. [Required(ErrorMessage = "Surname is required")]
  7. public string Surname { get; set; } = null!;
  8. [Required(ErrorMessage = "Email is required")]
  9. public string Email { get; set; } = null!;
  10. [Required(ErrorMessage = "Password is required")]
  11. public string Password { get; set; } = null!;
  12. [Required(ErrorMessage = "Salary pay date is required")]
  13. public DateTime? SalaryPaymentDate { get; set; }
  14. [Required(ErrorMessage = "Salary amount is required")]
  15. public Decimal? SalaryAmount { get; set; }
  16. [Required(ErrorMessage = "Currency is required")]
  17. public Guid? CurrencyID { get; set; }
  18. public Currency? Currency { get; set; }
  19. public List<CreditCard>? CreditCards { get; set; }
  20. public List<Saving>? Savings { get; set; }
  21. public List<Expense>? Expenses { get; set; }
  22. }

Currency 类:

  1. public class Currency
  2. {
  3. public Guid CurrencyID { get; set; }
  4. public string CurrencyName { get; set; } = null!;
  5. public string CurrencyAbbreviation { get; set; } = null!;
  6. public string? CurrencySymbol { get; set; }
  7. public List<ApplicationUser>? ApplicationUsers { get; set; }
  8. }

我已经为Currency类添加了三个值,分别是:

  • USD
  • ZAR
  • Euro

Saving 类:

  1. public class Saving
  2. {
  3. public Guid SavingID { get; set; }
  4. public List<Goal>? Goals { get; set; }
  5. public Guid? ApplicationUserID { get; set; }
  6. public ApplicationUser? ApplicationUser { get; set; }
  7. }

我正在尝试的是,当您首次打开储蓄视图并且Get方法返回0个值时,我会创建一个新的SavingObject

在这个SavingObject中,我分配了作为级联参数传递的CurrentUser,它确实有一个值。

然后我运行我的AddMethod来创建储蓄对象。以下是该方法:

  1. [CascadingParameter]
  2. public ApplicationUser? CurrentUser { get; set; }
  3. protected override async Task OnInitializedAsync()
  4. {
  5. Savings = await savingsservice.Get();
  6. if (Savings?.Count > 0)
  7. SavingObject = Savings.FirstOrDefault();
  8. else
  9. {
  10. SavingObject = new Saving();
  11. SavingObject.ApplicationUser = CurrentUser!;
  12. SavingObject.ApplicationUserID = CurrentUser!.ApplicationUserID;
  13. await savingsservice.Add(SavingObject);
  14. DataChanged();
  15. }
  16. Goals = await goalsservice.Get();
  17. }

但一旦运行add方法,它就崩溃,并显示以下消息:

Microsoft.EntityFrameworkCore.DbUpdateException: 保存实体更改时发生错误。有关详细信息,请参见内部异常。
Microsoft.Data.SqlClient.SqlException (0x80131904): 在对象'dbo.Currencies'中的'PK_Currencies'主键约束违规。不能在对象'dbo.Currencies'中插入重复的键。重复的键值是(c80b1fe5-7d94-4fc5-8328-706db7f29a18)。
在对象'dbo.ApplicationUsers'中的'PK_ApplicationUsers'主键约束违规。不能在对象'dbo.ApplicationUsers'中插入重复的键。重复的键值是(1d03c731-3034-498b-fef5-08db0eaad3f6)。

我理解它说不能为用户和货币插入重复键,但为什么它要插入重复键,我不理解,因为我已经为用户分配了ID和CurrencyID

此外,我的Savings表是空的,我的表中只有一个applicationUser,它有一个Currency

请有人帮忙,因为我在网上找不到答案。

我已经设置了dbcontext,因为我认为这可能是问题所在。

  1. modelBuilder.Entity<ApplicationUser>()
  2. .HasMany(a => a.Savings)
  3. .WithOne(a => a.ApplicationUser)
  4. .HasForeignKey(a => a.ApplicationUserID)
  5. .OnDelete(DeleteBehavior.Cascade);
  6. modelBuilder.Entity<ApplicationUser>()
  7. .HasMany(a => a.CreditCards)
  8. .WithOne(a => a.ApplicationUser)
  9. .HasForeignKey(a => a.ApplicationUserID)
  10. .OnDelete(DeleteBehavior.Cascade);
  11. modelBuilder.Entity<ApplicationUser>()
  12. .HasMany(a => a.Expenses)
  13. .WithOne(a => a.ApplicationUser)
  14. .HasForeignKey(a => a.ApplicationUserID)
  15. .OnDelete(DeleteBehavior.Cascade);

这是我的Savings.cs服务:

  1. namespace MoneyTracker.Services
  2. {
  3. public interface ISavingsService
  4. {
  5. Task<List<Saving>> Get();
  6. Task<Saving> Get(Guid id);
  7. Task<Saving> Add(Saving Saving);
  8. Task<Saving> Update(Saving Saving);
  9. Task<Saving> Delete(Guid id);
  10. void DetachEntity(Saving Saving);
  11. }
  12. public class SavingsService : ISavingsService
  13. {
  14. private readonly ApplicationDbContext _context;
  15. public SavingsService(ApplicationDbContext context)
  16. {
  17. _context = context;
  18. }
  19. public async Task<List<Saving>> Get()
  20. {
  21. return await _context.Savings
  22. .Include(a => a.Goals)
  23. .AsSplitQuery()
  24. .ToListAsync();
  25. }
  26. public async Task<Saving> Get(Guid id)
  27. {
  28. var Saving = await _context.Savings.FindAsync(id);
  29. return Saving;
  30. }
  31. public async Task<Saving> Add(Saving Saving)
  32. {
  33. _context.Savings.Add(Saving);
  34. await _context.SaveChangesAsync();
  35. return Saving;
  36. }
  37. public async Task<Saving> Update(Saving Saving)
  38. {
  39. _context.Entry(Saving).State = EntityState.Modified;
  40. await _context.SaveChangesAsync();
  41. return Saving;
  42. }
  43. public async Task<Saving> Delete(Guid id)
  44. {
  45. var Saving = await _context.Savings.FindAsync(id);
  46. _context.Savings.Remove(Saving);
  47. await _context.SaveChangesAsync();
  48. return Saving;
  49. }
  50. public void DetachEntity(Saving Saving)
  51. {
  52. _context.Entry(Saving).State = EntityState.Detached;
  53. }
  54. }
  55. }
英文:

I am working on blazor server. I have the following class structure for my project.

I have for this error three classes.

ApplicationUser class:

  1. public class ApplicationUser
  2. {
  3. public Guid ApplicationUserID { get; set; }
  4. [Required (ErrorMessage = &quot;Name is required&quot;)]
  5. public string Name { get; set; } = null!;
  6. [Required(ErrorMessage = &quot;Surname is required&quot;)]
  7. public string Surname { get; set; } = null!;
  8. [Required(ErrorMessage = &quot;Email is required&quot;)]
  9. public string Email { get; set; } = null!;
  10. [Required(ErrorMessage = &quot;Password is required&quot;)]
  11. public string Password { get; set; } = null!;
  12. [Required(ErrorMessage = &quot;Salary pay date is required&quot;)]
  13. public DateTime? SalaryPaymentDate { get; set; }
  14. [Required(ErrorMessage = &quot;Salary amount is required&quot;)]
  15. public Decimal? SalaryAmount { get; set; }
  16. [Required (ErrorMessage = &quot;Currency is required&quot;)]
  17. public Guid? CurrencyID { get; set; }
  18. public Currency? Currency { get; set; }
  19. public List&lt;CreditCard&gt;? CreditCards { get; set;}
  20. public List&lt;Saving&gt;? Savings { get; set;}
  21. public List&lt;Expense&gt;? Expenses { get; set;}
  22. }

Currency class:

  1. public class Currency
  2. {
  3. public Guid CurrencyID { get; set; }
  4. public string CurrencyName { get; set; } = null!;
  5. public string CurrencyAbbreviation { get; set; } = null!;
  6. public string? CurrencySymbol { get; set; }
  7. public List&lt;ApplicationUser&gt;? ApplicationUsers { get; set; }
  8. }
  1. I seeded the currency class with three values namely:
  2. - USD
  3. - ZAR
  4. - Euro
  5. `Savings` class:
  6. public class Saving
  7. {
  8. public Guid SavingID { get; set; }
  9. public List&lt;Goal&gt;? Goals { get; set; }
  10. public Guid? ApplicationUserID { get; set; }
  11. public ApplicationUser? ApplicationUser { get; set; }
  12. }

So what I am trying to do is when you open the savings view for the first time and the Get method returns 0 values I create a new SavingObject.

In this SavingObject, I assign the CurrentUser which is passed as a cascading parameter and it does have a value.

Then I run my AddMethod to create the saving object. Here is the method:

  1. [CascadingParameter]
  2. public ApplicationUser? CurrentUser { get; set; }
  3. protected override async Task OnInitializedAsync()
  4. {
  5. Savings = await savingsservice.Get();
  6. if (Savings?.Count &gt; 0)
  7. SavingObject = Savings.FirstOrDefault();
  8. else
  9. {
  10. SavingObject = new Saving();
  11. SavingObject.ApplicationUser = CurrentUser!;
  12. SavingObject.ApplicationUserID = CurrentUser!.ApplicationUserID;
  13. await savingsservice.Add(SavingObject);
  14. DataChanged();
  15. }
  16. Goals = await goalsservice.Get();
  17. }

But it then crashes with the following message once the add method is run:

> Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
>
> Microsoft.Data.SqlClient.SqlException (0x80131904): Violation of PRIMARY KEY constraint 'PK_Currencies'. Cannot insert duplicate key in object 'dbo.Currencies'. The duplicate key value is (c80b1fe5-7d94-4fc5-8328-706db7f29a18).
>
> Violation of PRIMARY KEY constraint 'PK_ApplicationUsers'. Cannot insert duplicate key in object 'dbo.ApplicationUsers'. The duplicate key value is (1d03c731-3034-498b-fef5-08db0eaad3f6).

I understand that it states cannot insert duplicate key for the user and currency but why does it want to insert a duplicate key I don't understand because I am assigning the user so it already has the ID and the CurrencyID?

Also my Savings table is empty and I only have one applicationUser in my table which has one Currency.

Can someone please assist as I can't find any answer online.

I have googled the problem but I can't find my specific problem online therefore I am creating a question.

I have also setup the dbcontext as I thought this might have been the problem.

  1. modelBuilder.Entity&lt;ApplicationUser&gt;()
  2. .HasMany(a =&gt; a.Savings)
  3. .WithOne(a =&gt; a.ApplicationUser)
  4. .HasForeignKey(a =&gt; a.ApplicationUserID)
  5. .OnDelete(DeleteBehavior.Cascade);
  6. modelBuilder.Entity&lt;ApplicationUser&gt;()
  7. .HasMany(a =&gt; a.CreditCards)
  8. .WithOne(a =&gt; a.ApplicationUser)
  9. .HasForeignKey(a =&gt; a.ApplicationUserID)
  10. .OnDelete(DeleteBehavior.Cascade);
  11. modelBuilder.Entity&lt;ApplicationUser&gt;()
  12. .HasMany(a =&gt; a.Expenses)
  13. .WithOne(a =&gt; a.ApplicationUser)
  14. .HasForeignKey(a =&gt; a.ApplicationUserID)
  15. .OnDelete(DeleteBehavior.Cascade);

Here is my Savings.cs service:

  1. namespace MoneyTracker.Services
  2. {
  3. public interface ISavingsService
  4. {
  5. Task&lt;List&lt;Saving&gt;&gt; Get();
  6. Task&lt;Saving&gt; Get(Guid id);
  7. Task&lt;Saving&gt; Add(Saving Saving);
  8. Task&lt;Saving&gt; Update(Saving Saving);
  9. Task&lt;Saving&gt; Delete(Guid id);
  10. void DetachEntity(Saving Saving);
  11. }
  12. public class SavingsService : ISavingsService
  13. {
  14. private readonly ApplicationDbContext _context;
  15. public SavingsService(ApplicationDbContext context)
  16. {
  17. _context = context;
  18. }
  19. public async Task&lt;List&lt;Saving&gt;&gt; Get()
  20. {
  21. return await _context.Savings
  22. .Include(a =&gt; a.Goals)
  23. .AsSplitQuery()
  24. .ToListAsync();
  25. }
  26. public async Task&lt;Saving&gt; Get(Guid id)
  27. {
  28. var Saving = await _context.Savings.FindAsync(id);
  29. return Saving;
  30. }
  31. public async Task&lt;Saving&gt; Add(Saving Saving)
  32. {
  33. _context.Savings.Add(Saving);
  34. await _context.SaveChangesAsync();
  35. return Saving;
  36. }
  37. public async Task&lt;Saving&gt; Update(Saving Saving)
  38. {
  39. _context.Entry(Saving).State = EntityState.Modified;
  40. await _context.SaveChangesAsync();
  41. return Saving;
  42. }
  43. public async Task&lt;Saving&gt; Delete(Guid id)
  44. {
  45. var Saving = await _context.Savings.FindAsync(id);
  46. _context.Savings.Remove(Saving);
  47. await _context.SaveChangesAsync();
  48. return Saving;
  49. }
  50. public void DetachEntity(Saving Saving)
  51. {
  52. _context.Entry(Saving).State = EntityState.Detached;
  53. }
  54. }
  55. }

答案1

得分: 2

我已经解决了我的问题。

问题发生的原因是,当我将 SavingObject 分配给 GoalObject 时,它没有被添加到上下文中。所以当我尝试在 goalObject 上运行添加方法时,它也尝试添加 savingObject,因为它在上下文中找不到。

另外,在 ServiceAddMethod 中我注意到的一件事是,当我添加一个新目标并在断点处打开 GoalObject 时,我可以看到 SavingsObject.Goals count was 1 而不是 null。使用以下方法解决了问题。

当我分配了 goal.Saving = saving 后,在这里检查时,目标的数量是 null,这阻止了重复的主键错误。

我真诚希望这可以帮助有人,因为我曾经为这个错误苦苦挣扎。

英文:

I have managed to resolve my problem.

The reason the problem had occurred was because when I assigned the SavingObject to the GoalObject it was not added to the context. So when I was trying to run the add method on the goalObject it also attempted to add the savingObject because it was not found on the context.

Also the thing I noted in the AddMethod of the Service was that when I would add a new goal and I opended the GoalObject with a breakpoint I could see the SavingsObject.Goals count was 1 not null. With the following method it resolved the problem.

  1. var saving = await _context.Savings.FindAsync(goal.SavingID);
  2. var user = await _context.ApplicationUsers.FindAsync(goal.Saving!.ApplicationUserID);
  3. if (saving == null || user == null)
  4. {
  5. throw new Exception(&quot;Saving with the specified ID not found&quot;);
  6. }
  7. saving.ApplicationUser = user;
  8. goal.Saving = saving;
  9. _context.Goals.Add(goal);
  10. await _context.SaveChangesAsync();
  11. return goal;

When I inspected here after I assigned the goal.Saving = saving the count of the goals was null and this prevented the error Duplicate PK error

I really hope this helps someone as I struggled a lot with this error.

huangapple
  • 本文由 发表于 2023年2月19日 16:37:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75498907.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定