EF Core-在添加具有唯一索引的数据时出现重复键错误

时间:2019-03-20 21:33:59

标签: c# entity-framework ef-code-first entity-framework-core ef-code-first-mapping

我正在尝试使用EF Core将数据添加到数据库中,但是我无法克服重复的键错误:Cannot insert duplicate key row in object 'dbo.Stocks' with unique index 'IX_Stocks_Name'. The duplicate key value is (stock1).

我有一个实体StockTransaction一对多关系-一个Stock可以与许多Transaction相关。

仅当数据库中不存在具有给定ID的Stock时,问题才不会发生-在这种情况下,我可以添加许多具有相同Transaction的{​​{1}} :

StockID

下面,我在类的using(var context = dbContextFactory.CreateDbContext(new string[0])) { List<Transaction> list = new List<Transaction>(); //If there's no Stock with ID "stock1" in the database the code works. //Executing the code for the second time results in error, however, if I changed stock1 to stock2 it would work var stock1 = new Stock("stock1"); list.AddRange(new Transaction[] { //I can add two exactly the same `Transaction`s and it's ok when executed on a fresh database new Transaction(stock1, DateTime.Now, 1M, 5), new Transaction(stock1, DateTime.Now, 1M, 5), }); context.Transactions.AddRange(list); context.SaveChanges(); } 中添加了类的定义。

预先感谢您的提示。

IEntityTypeConfiguration类:

Transaction

public class Transaction { public Stock RelatedStock { get; set; } public DateTime TransactionTime { get; set; } public Decimal Price { get; set; } public int Volume { get; set; } public Transaction() { } } 类:

TransactionConfiguration

public class TransactionConfiguration : IEntityTypeConfiguration<Transaction> { public void Configure(EntityTypeBuilder<Transaction> builder) { builder .ToTable("Transactions"); builder .Property<int>("TransactionID") .HasColumnType("int") .ValueGeneratedOnAdd() .HasAnnotation("Key", 0); builder .Property(transaction => transaction.Price) .HasColumnName("Price") .IsRequired(); builder .Property(transaction => transaction.TransactionTime) .HasColumnName("Time") .IsRequired(); builder .Property(transaction => transaction.Volume) .HasColumnName("Volume") .IsRequired(); builder .HasIndex("RelatedStockStockID", nameof(Transaction.TransactionTime)) .IsUnique(); } } 类:

Stock

public class Stock { public string Name { get; set; } public ICollection<Transaction> Transactions { get; set; } public Stock() { } } 类:

StockConfiguration

3 个答案:

答案 0 :(得分:1)

dbo.Stocks表上有一个唯一索引,名为IX_Stocks_Name。您违反了该索引。

您的问题是这一行:

var stock1 = new Stock("stock1");

您正在反复创建“ stock1”。相反,您应该首先为“ stock1”检索(或存储)Stock实体,并使用它(如果已经存在)。如果不存在,则可以安全地创建一个。

简而言之,代码使用现有的INSERTdbo.Stocks插入Name

答案 1 :(得分:0)

您需要检查是否存在已知所需ID的库存。为了您的示例:

var stock1 = context.Stocks.SingleOrDefault(x => x.StockId == "stock1") ?? new Stock("stock1");

如果数据库中已有股票,它将与现有股票相关联;如果数据库中没有股票,则将与新股票相关联。

答案 2 :(得分:0)

由于@ Zer0和@Steve Py的建议,我提出了以下解决方案:

void Insert(IEnumerable<Transaction> data)
        {
            using(var context = dbContextFactory.CreateDbContext(new string[0]))
            {
                List<Stock> stocks = data.Select(s => s.RelatedStock).Distinct(new StockComparer()).ToList();
                context.AddRange(stocks);
                context.SaveChanges();
                stocks = context.Stocks.ToList();

                List<Transaction> newList = new List<Transaction>(data.Count());

                foreach (var t in data)
                {
                        Stock relatedStock = stocks.Where(s => s.Name == t.RelatedStock.Name).First();
                        t.RelatedStock = relatedStock;
                        newList.Add(t);
                }

                context.Transactions.AddRange(newList);
                context.SaveChanges();
            }
        }