英文:
Violation of PRIMARY KEY constraint 'PK_Currencies'. Cannot insert duplicate key in object
问题
我正在使用Blazor服务器开发项目。我有以下类结构用于我的项目。
我有三个类来处理这个错误。
ApplicationUser
类:
public class ApplicationUser
{
public Guid ApplicationUserID { get; set; }
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; } = null!;
[Required(ErrorMessage = "Surname is required")]
public string Surname { get; set; } = null!;
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; } = null!;
[Required(ErrorMessage = "Password is required")]
public string Password { get; set; } = null!;
[Required(ErrorMessage = "Salary pay date is required")]
public DateTime? SalaryPaymentDate { get; set; }
[Required(ErrorMessage = "Salary amount is required")]
public Decimal? SalaryAmount { get; set; }
[Required(ErrorMessage = "Currency is required")]
public Guid? CurrencyID { get; set; }
public Currency? Currency { get; set; }
public List<CreditCard>? CreditCards { get; set; }
public List<Saving>? Savings { get; set; }
public List<Expense>? Expenses { get; set; }
}
Currency
类:
public class Currency
{
public Guid CurrencyID { get; set; }
public string CurrencyName { get; set; } = null!;
public string CurrencyAbbreviation { get; set; } = null!;
public string? CurrencySymbol { get; set; }
public List<ApplicationUser>? ApplicationUsers { get; set; }
}
我已经为Currency
类添加了三个值,分别是:
- USD
- ZAR
- Euro
Saving
类:
public class Saving
{
public Guid SavingID { get; set; }
public List<Goal>? Goals { get; set; }
public Guid? ApplicationUserID { get; set; }
public ApplicationUser? ApplicationUser { get; set; }
}
我正在尝试的是,当您首次打开储蓄视图并且Get
方法返回0个值时,我会创建一个新的SavingObject
。
在这个SavingObject
中,我分配了作为级联参数传递的CurrentUser
,它确实有一个值。
然后我运行我的AddMethod
来创建储蓄对象。以下是该方法:
[CascadingParameter]
public ApplicationUser? CurrentUser { get; set; }
protected override async Task OnInitializedAsync()
{
Savings = await savingsservice.Get();
if (Savings?.Count > 0)
SavingObject = Savings.FirstOrDefault();
else
{
SavingObject = new Saving();
SavingObject.ApplicationUser = CurrentUser!;
SavingObject.ApplicationUserID = CurrentUser!.ApplicationUserID;
await savingsservice.Add(SavingObject);
DataChanged();
}
Goals = await goalsservice.Get();
}
但一旦运行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
,因为我认为这可能是问题所在。
modelBuilder.Entity<ApplicationUser>()
.HasMany(a => a.Savings)
.WithOne(a => a.ApplicationUser)
.HasForeignKey(a => a.ApplicationUserID)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ApplicationUser>()
.HasMany(a => a.CreditCards)
.WithOne(a => a.ApplicationUser)
.HasForeignKey(a => a.ApplicationUserID)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ApplicationUser>()
.HasMany(a => a.Expenses)
.WithOne(a => a.ApplicationUser)
.HasForeignKey(a => a.ApplicationUserID)
.OnDelete(DeleteBehavior.Cascade);
这是我的Savings.cs
服务:
namespace MoneyTracker.Services
{
public interface ISavingsService
{
Task<List<Saving>> Get();
Task<Saving> Get(Guid id);
Task<Saving> Add(Saving Saving);
Task<Saving> Update(Saving Saving);
Task<Saving> Delete(Guid id);
void DetachEntity(Saving Saving);
}
public class SavingsService : ISavingsService
{
private readonly ApplicationDbContext _context;
public SavingsService(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<Saving>> Get()
{
return await _context.Savings
.Include(a => a.Goals)
.AsSplitQuery()
.ToListAsync();
}
public async Task<Saving> Get(Guid id)
{
var Saving = await _context.Savings.FindAsync(id);
return Saving;
}
public async Task<Saving> Add(Saving Saving)
{
_context.Savings.Add(Saving);
await _context.SaveChangesAsync();
return Saving;
}
public async Task<Saving> Update(Saving Saving)
{
_context.Entry(Saving).State = EntityState.Modified;
await _context.SaveChangesAsync();
return Saving;
}
public async Task<Saving> Delete(Guid id)
{
var Saving = await _context.Savings.FindAsync(id);
_context.Savings.Remove(Saving);
await _context.SaveChangesAsync();
return Saving;
}
public void DetachEntity(Saving Saving)
{
_context.Entry(Saving).State = EntityState.Detached;
}
}
}
英文:
I am working on blazor server. I have the following class structure for my project.
I have for this error three classes.
ApplicationUser
class:
public class ApplicationUser
{
public Guid ApplicationUserID { get; set; }
[Required (ErrorMessage = "Name is required")]
public string Name { get; set; } = null!;
[Required(ErrorMessage = "Surname is required")]
public string Surname { get; set; } = null!;
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; } = null!;
[Required(ErrorMessage = "Password is required")]
public string Password { get; set; } = null!;
[Required(ErrorMessage = "Salary pay date is required")]
public DateTime? SalaryPaymentDate { get; set; }
[Required(ErrorMessage = "Salary amount is required")]
public Decimal? SalaryAmount { get; set; }
[Required (ErrorMessage = "Currency is required")]
public Guid? CurrencyID { get; set; }
public Currency? Currency { get; set; }
public List<CreditCard>? CreditCards { get; set;}
public List<Saving>? Savings { get; set;}
public List<Expense>? Expenses { get; set;}
}
Currency
class:
public class Currency
{
public Guid CurrencyID { get; set; }
public string CurrencyName { get; set; } = null!;
public string CurrencyAbbreviation { get; set; } = null!;
public string? CurrencySymbol { get; set; }
public List<ApplicationUser>? ApplicationUsers { get; set; }
}
I seeded the currency class with three values namely:
- USD
- ZAR
- Euro
`Savings` class:
public class Saving
{
public Guid SavingID { get; set; }
public List<Goal>? Goals { get; set; }
public Guid? ApplicationUserID { get; set; }
public ApplicationUser? ApplicationUser { get; set; }
}
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:
[CascadingParameter]
public ApplicationUser? CurrentUser { get; set; }
protected override async Task OnInitializedAsync()
{
Savings = await savingsservice.Get();
if (Savings?.Count > 0)
SavingObject = Savings.FirstOrDefault();
else
{
SavingObject = new Saving();
SavingObject.ApplicationUser = CurrentUser!;
SavingObject.ApplicationUserID = CurrentUser!.ApplicationUserID;
await savingsservice.Add(SavingObject);
DataChanged();
}
Goals = await goalsservice.Get();
}
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.
modelBuilder.Entity<ApplicationUser>()
.HasMany(a => a.Savings)
.WithOne(a => a.ApplicationUser)
.HasForeignKey(a => a.ApplicationUserID)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ApplicationUser>()
.HasMany(a => a.CreditCards)
.WithOne(a => a.ApplicationUser)
.HasForeignKey(a => a.ApplicationUserID)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ApplicationUser>()
.HasMany(a => a.Expenses)
.WithOne(a => a.ApplicationUser)
.HasForeignKey(a => a.ApplicationUserID)
.OnDelete(DeleteBehavior.Cascade);
Here is my Savings.cs service:
namespace MoneyTracker.Services
{
public interface ISavingsService
{
Task<List<Saving>> Get();
Task<Saving> Get(Guid id);
Task<Saving> Add(Saving Saving);
Task<Saving> Update(Saving Saving);
Task<Saving> Delete(Guid id);
void DetachEntity(Saving Saving);
}
public class SavingsService : ISavingsService
{
private readonly ApplicationDbContext _context;
public SavingsService(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<Saving>> Get()
{
return await _context.Savings
.Include(a => a.Goals)
.AsSplitQuery()
.ToListAsync();
}
public async Task<Saving> Get(Guid id)
{
var Saving = await _context.Savings.FindAsync(id);
return Saving;
}
public async Task<Saving> Add(Saving Saving)
{
_context.Savings.Add(Saving);
await _context.SaveChangesAsync();
return Saving;
}
public async Task<Saving> Update(Saving Saving)
{
_context.Entry(Saving).State = EntityState.Modified;
await _context.SaveChangesAsync();
return Saving;
}
public async Task<Saving> Delete(Guid id)
{
var Saving = await _context.Savings.FindAsync(id);
_context.Savings.Remove(Saving);
await _context.SaveChangesAsync();
return Saving;
}
public void DetachEntity(Saving Saving)
{
_context.Entry(Saving).State = EntityState.Detached;
}
}
}
答案1
得分: 2
我已经解决了我的问题。
问题发生的原因是,当我将 SavingObject
分配给 GoalObject
时,它没有被添加到上下文中。所以当我尝试在 goalObject
上运行添加方法时,它也尝试添加 savingObject
,因为它在上下文中找不到。
另外,在 Service
的 AddMethod
中我注意到的一件事是,当我添加一个新目标并在断点处打开 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.
var saving = await _context.Savings.FindAsync(goal.SavingID);
var user = await _context.ApplicationUsers.FindAsync(goal.Saving!.ApplicationUserID);
if (saving == null || user == null)
{
throw new Exception("Saving with the specified ID not found");
}
saving.ApplicationUser = user;
goal.Saving = saving;
_context.Goals.Add(goal);
await _context.SaveChangesAsync();
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论