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

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

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 = &quot;Name is required&quot;)]
    public string Name { get; set; } = null!;
    [Required(ErrorMessage = &quot;Surname is required&quot;)]
    public string Surname { get; set; } = null!;
    [Required(ErrorMessage = &quot;Email is required&quot;)]
    public string Email { get; set; } = null!;
    [Required(ErrorMessage = &quot;Password is required&quot;)]
    public string Password { get; set; } = null!;
    [Required(ErrorMessage = &quot;Salary pay date is required&quot;)]
    public DateTime? SalaryPaymentDate { get; set; }
    [Required(ErrorMessage = &quot;Salary amount is required&quot;)]
    public Decimal? SalaryAmount { get; set; }
    [Required (ErrorMessage = &quot;Currency is required&quot;)]
    public Guid? CurrencyID { get; set; }
    public Currency? Currency { get; set; }
    public List&lt;CreditCard&gt;? CreditCards { get; set;}
    public List&lt;Saving&gt;? Savings { get; set;}
    public List&lt;Expense&gt;? 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&lt;ApplicationUser&gt;? 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&lt;Goal&gt;? 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 &gt; 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&lt;ApplicationUser&gt;()
        .HasMany(a =&gt; a.Savings)
        .WithOne(a =&gt; a.ApplicationUser)
        .HasForeignKey(a =&gt; a.ApplicationUserID)
        .OnDelete(DeleteBehavior.Cascade);

modelBuilder.Entity&lt;ApplicationUser&gt;()
        .HasMany(a =&gt; a.CreditCards)
        .WithOne(a =&gt; a.ApplicationUser)
        .HasForeignKey(a =&gt; a.ApplicationUserID)
        .OnDelete(DeleteBehavior.Cascade);

modelBuilder.Entity&lt;ApplicationUser&gt;()
        .HasMany(a =&gt; a.Expenses)
        .WithOne(a =&gt; a.ApplicationUser)
        .HasForeignKey(a =&gt; a.ApplicationUserID)
        .OnDelete(DeleteBehavior.Cascade);

Here is my Savings.cs service:

namespace MoneyTracker.Services
{
    public interface ISavingsService
    {
        Task&lt;List&lt;Saving&gt;&gt; Get();
        Task&lt;Saving&gt; Get(Guid id);
        Task&lt;Saving&gt; Add(Saving Saving);
        Task&lt;Saving&gt; Update(Saving Saving);
        Task&lt;Saving&gt; Delete(Guid id);
        void DetachEntity(Saving Saving);
    }
    public class SavingsService : ISavingsService
    {
        private readonly ApplicationDbContext _context;

        public SavingsService(ApplicationDbContext context)
        {
            _context = context;
        }

        public async Task&lt;List&lt;Saving&gt;&gt; Get()
        {
            return await _context.Savings
                .Include(a =&gt; a.Goals)
                .AsSplitQuery()
                .ToListAsync();
        }
        public async Task&lt;Saving&gt; Get(Guid id)
        {
            var Saving = await _context.Savings.FindAsync(id);
            return Saving;
        }

        public async Task&lt;Saving&gt; Add(Saving Saving)
        {
            _context.Savings.Add(Saving);
            await _context.SaveChangesAsync();
            return Saving;
        }
        public async Task&lt;Saving&gt; Update(Saving Saving)
        {
            _context.Entry(Saving).State = EntityState.Modified;
            await _context.SaveChangesAsync();
            return Saving;
        }
        public async Task&lt;Saving&gt; 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,因为它在上下文中找不到。

另外,在 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.

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(&quot;Saving with the specified ID not found&quot;);
}

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.

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:

确定