在将.Net与其他数据库一起使用多年之后,我只是在重新学习SQLServer。
我正在使用Microsoft.EntityFrameworkCore;
我在SQLServer中有一个1表数据库。从该表中,我已使用实体框架来生成模型。该表具有主键(自动递增)和唯一键(表的三列上的自然键)。
由EF生成的模型已为唯一键索引生成了代码:
entity.HasIndex(e => new { e.Col1, e.Col2, e.Col3})
.HasName("MyTable_UK")
.IsUnique();
我正在使用db.MyTable.Add(myRow);向DbSet添加多行。无需立即调用SaveChanges。
我期待db.MyTable.Add(myRow);违反唯一索引时引发异常。它不是;它允许DbSet中有重复的行。当我将更改保存到数据库时,我得到了英国违规作为例外。
在调用SaveChanges之前,有什么方法可以使它引发异常吗?它似乎具有执行此操作所需的所有信息。
答案 0 :(得分:2)
您可以轻松地编写查询来检查您要插入的记录是否已经存在:
if (!db.MyTable.Any(e => e.Col1 == myRow.Col1 && e.Col2 == myRow.Col2 && e.Col3 == myRow.Col3))
{
db.MyTable.Add(myRow);
}
else {
// You can throw an exception here if you'd like but I usually prefer to return 'false' or some other indicator.
}
答案 1 :(得分:1)
将SaveChanges
封装为try...catch
块始终是验证数据库操作的正确和简单方法。
if (ModelState.IsValid)
{
try
{
_context.Add(data);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch (DbUpdateException ex)
{
if (ex.InnerException is SqlException innerException)
{
// handle exception here..
ModelState.AddModelError("Col1", yourmessage1);
}
else
{
ModelState.AddModelError("Col1", yourmessage2);
}
}
catch (Exception ex)
{
ModelState.AddModelError("Col1", ex.Message);
}
}
return View();
但是,如果您想使事情变得复杂,这是正确的方法:
假设这是您的实体
public class Example
{
[Key, Column(Order = 0)]
public int Col1 { get; set; }
[Key, Column(Order = 1)]
public int Col2 { get; set; }
[Key, Column(Order = 2)]
public int Col3 { get; set; }
public string Data { get; set; }
}
public class MyDbContext : DbContext
{
public virtual DbSet<Example> Examples { get; set; }
public override int SaveChanges()
{
ValidateEntities();
return base.SaveChanges();
}
private void ValidateEntities()
{
var hasChanges = ChangeTracker.Entries()
.Any(x => (x.Entity is Example) && (x.State == EntityState.Added || x.State == EntityState.Modified));
if (!hasChanges)
{
return;
}
var addedEntries = ChangeTracker.Entries()
.Where(x => (x.Entity is Example) && x.State == EntityState.Added)
.Select(x => x.Entity as Example);
// The tricky is right here: this.Examples.Where(...), will it execute in DB or local?
var existingEntities = this.Examples.Where(x => addedEntries.Any(e => e.Col1 == x.Col1 && e.Col2 == x.Col2 && x.Col3 == e.Col3));
if (existingEntities.Any())
{
var keys = string.Join("; ", existingEntities.Select(x => $"{x.Col1}-{x.Col2}-{x.Col3}"));
throw new Exception($"{keys} already exist.");
}
var modifiedEntries = ChangeTracker.Entries()
.Where(x => (x.Entity is Brand) && x.State == EntityState.Modified);
if (modifiedEntries.Any())
{
return;
}
////TO DO: the rest code for modified entries, more complex than added part.
}
}