我正在尝试使用EF Core将数据添加到数据库中,但是我无法克服重复的键错误:Cannot insert duplicate key row in object 'dbo.Stocks' with unique index 'IX_Stocks_Name'. The duplicate key value is (stock1).
我有一个实体Stock
与Transaction
一对多关系-一个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
答案 0 :(得分:1)
dbo.Stocks
表上有一个唯一索引,名为IX_Stocks_Name
。您违反了该索引。
您的问题是这一行:
var stock1 = new Stock("stock1");
您正在反复创建“ stock1”。相反,您应该首先为“ stock1”检索(或存储)Stock
实体,并使用它(如果已经存在)。如果不存在,则可以安全地创建一个。
简而言之,代码使用现有的INSERT
将dbo.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();
}
}