更新记录时出现 SQLite 错误 19: 'UNIQUE constraint failed' with Entity Framework Core

Getting a SQLite Error 19: 'UNIQUE constraint failed' with Entity Framework Core when updating a record

我有一个发票对象,其中有一个客户对象 属性。当我尝试更新我的发票对象时,我收到此 SQLite 错误 19: 'UNIQUE constraint failed: Client.InvoiceId'。我尝试按照另一篇关于同一问题的文章的建议进行操作,即在调用 SaveChanges() 之前添加一条 Attach 语句,但这没有用:

_context.Invoices.Attach(invoice);

这是我的数据模型:

public class Invoice
    {
        public string InvoiceId { get; set; } = GenerateID.GenerateInvoiceID();
        public string Description { get; set; }
        public List<InvoiceItem> Items { get; set; }
        public DateTime InvoiceDate { get; set; }
        public string PaymentTerms { get; set; }
        public DateTime PaymentDue { get; set; }
        public int TotalPrice { get; set; }
        public string Status { get; set; } = "pending";
        public Client Client { get; set; }
        

        public string BillFromAddress { get; set; }
        public string BillFromCity { get; set; }
        public string BillFromCountry { get; set; }
        public string BillFromPostal { get; set; }

    }

public class Client
    {
        public string ClientId{ get; set; } = GenerateID.GenerateClientID();
        public string InvoiceId { get; set; }
        [Required]
        public string ClientName { get; set; }
        [Required]
        public string ClientEmail { get; set; }
        [Required]
        public string ClientAddress { get; set; }
        [Required]
        public string ClientCity { get; set; }
        [Required]
        public string ClientCountry { get; set; }
        [Required]
        public string ClientPostal { get; set; }
   
    }

public class InvoiceItem
    {
        public string InvoiceItemId { get; set; } = GenerateID.GenerateItemID();
        public string InvoiceId { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public int Quantity { get; set; }
        [Required]
        public int Price { get; set; }

        public InvoiceItem()
        {
        }

        public InvoiceItem(string itemName, int quantity, int price)
        {
            Name = itemName;
            Quantity = quantity;
            Price = price;
        }  
    }

这是更新发票的服务:

public async void EditInvoice(InputModel input, string id)
        {
            var invoice = await _context.Invoices.FindAsync(id);

            if (invoice == null) { throw new Exception("Unable to find the invoice"); }

            invoice.Items = input.Items;

            invoice.Description = input.Description;
            invoice.InvoiceDate = input.InvoiceDate;
            invoice.PaymentTerms = input.PaymentTerms;
            invoice.Client = input.Client;

            
            invoice.BillFromAddress = input.BillFromAddress;
            invoice.BillFromCity = input.BillFromCity;
            invoice.BillFromCountry = input.BillFromCountry;
            invoice.BillFromPostal = input.BillFromPostal;

            await _context.SaveChangesAsync();
        }

这是我的 InputModel class:

public class InputModel
    {
        [Required]
        public string Description { get; set; }

        [Required]
        [DataType(DataType.Date)]
        public DateTime InvoiceDate { get; set; }

        public string PaymentTerms { get; set; }
        public DateTime PaymentDue { get; set; }


        public Client Client { get; set; }

        
        public List<InvoiceItem> Items { get; set; } = new List<InvoiceItem>(16);


        [Required]
        public string BillFromAddress { get; set; }
        [Required]
        public string BillFromCity { get; set; }
        [Required]
        public string BillFromCountry { get; set; }
        [Required]
        public string BillFromPostal { get; set; }


        public void PopulateItems()
        {
            for (int i = 0; i < Items.Capacity; i++)
            {
                Items.Add(new InvoiceItem());
            }
        }
    }

这是我的 CreateInvoice PageModel

 public class CreateInvoiceModel : PageModel
    {
        
        public readonly InvoiceService _service;

        [BindProperty]
        public InputModel Input { get; set; }

        public CreateInvoiceModel(InvoiceService service)
        {
            _service = service;
        }


        public void OnGet()
        {
            Input = new InputModel();
            Input.PopulateItems();
        }


        public async Task<IActionResult> OnPost()
        {

            if (ModelState.IsValid)
            {
                _service.AddInvoice(Input);
                return RedirectToPage("/Index");
            }

            return Page();

        }

    }

这是我的 EditInvoice PageModel

public class EditInvoiceModel : PageModel
    {

        public readonly InvoiceService _service;

        [BindProperty]
        public InputModel Input { get; set; }

        public string InvoiceId { get; set; }

        public EditInvoiceModel(InvoiceService service)
        {
            _service = service;
        }

        
        public async void OnGet(string id)
        {
            Invoice invoice = await _service.GetInvoice(id);
            InvoiceId = invoice.InvoiceId;
            Input = new InputModel();

            Input.Items = invoice.Items;

            Input.BillFromAddress = invoice.BillFromAddress;
            Input.BillFromCity = invoice.BillFromCity;
            Input.BillFromPostal = invoice.BillFromPostal;
            Input.BillFromCountry = invoice.BillFromCountry;

            Input.Client = invoice.Client;

            Input.InvoiceDate = invoice.InvoiceDate;
            Input.PaymentTerms = invoice.PaymentTerms;
            Input.Description = invoice.Description;

        }

        public  async Task<IActionResult> OnPost(string id)
        {
           if(ModelState.IsValid)
            {
                _service.EditInvoice(Input, id);
                return RedirectToPage("/ViewInvoice", new { id = id });
            }

            return Page();
        }

    }

这是我的 DbContext class:

public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        {
        }

        public DbSet<Invoice> Invoices { get; set; }
    }

我假设正在发生的事情是 ChangeTracker 跟踪您在 EditInvoice 方法中设置为新实体的客户端,并尝试将其插入数据库。但是因为您将 Client 和 Invoice 映射为 1 对 1 关系,所以插入失败。

因此,由于一个客户真的可以拥有多张发票,因此您需要进行以下更改:

客户端
删除 InvoiceId

public class Client
{
    public string ClientId { get; set; } = GenerateID.GenerateClientID();
    // public string InvoiceId { get; set; }
    /* omitted for brevity */
}

真的删除这一行。我只是将其注释掉以使其清楚。

发票
添加 ClientId

public class Invoice
{
    public string InvoiceId { get; set; } = GenerateID.GenerateInvoiceID();
    public string ClientId { get; set; }
    /* omitted for brevity */
}

输入模型
Client 对象更改为 ClientId

public class InputModel
{
    // public Client Client { get; set; }
    public string ClientId { get; set; }
   /* omitted for brevity */
}

EditInvoice 方法
更新 ClientId 而不是整个 Client 对象

invoice.ClientId = input.ClientId;

您可以在 EntityFrameworkCore 中阅读更多关于关系的信息 here

如果这对你有用,请告诉我。