Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# DbSet<;tenty>;。添加(张力)和唯一性_C#_.net_Sql Server_Entity Framework Core - Fatal编程技术网

C# DbSet<;tenty>;。添加(张力)和唯一性

C# DbSet<;tenty>;。添加(张力)和唯一性,c#,.net,sql-server,entity-framework-core,C#,.net,Sql Server,Entity Framework Core,在将.Net与其他数据库一起使用多年后,我正在重新学习SQLServer 我正在使用Microsoft.EntityFrameworkCore 我在SQLServer中有一个1表数据库。从该表中,我使用实体框架生成了模型。该表有一个主键(自动递增)和一个唯一键(表的三列上的自然键) EF生成的模型已生成唯一键索引的代码: entity.HasIndex(e => new { e.Col1, e.Col2, e.Col3}) .HasName("MyT

在将.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)向数据库集添加多行;不立即调用SaveChanges

我期待db.MyTable.Add(myRow);在违反唯一索引时引发异常。它没有;它允许在数据库集中重复行。当我保存对数据库的更改时,我会得到UK违规作为一个例外


有没有办法让它在调用SaveChanges之前抛出异常?它似乎具有执行此操作所需的所有信息。

您可以轻松编写查询,以检查您尝试插入的记录是否已经存在:

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.
}

您可以轻松编写查询,以检查您尝试插入的记录是否已存在:

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.
}

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.
    }
}
公共类示例
{
[键,列(顺序=0)]
公共int Col1{get;set;}
[键,列(顺序=1)]
公共int Col2{get;set;}
[键,列(顺序=2)]
公共int Col3{get;set;}
公共字符串数据{get;set;}
}
公共类MyDbContext:DbContext
{
公共虚拟数据库集示例{get;set;}
公共覆盖int SaveChanges()
{
验证属性();
返回base.SaveChanges();
}
私有void ValidateEntities()
{
var hasChanges=ChangeTracker.Entries()
.Any(x=>(x.Entity为示例)和&(x.State==EntityState.Added | | x.State==EntityState.Modified));
如果(!hasChanges)
{
返回;
}
var addedEntries=ChangeTracker.Entries()
其中(x=>(以x.Entity为例)&&x.State==EntityState.Added)
.选择(x=>x.实体作为示例);
//棘手的问题就在这里:this.Examples.Where(…),它是在DB中执行还是在本地执行?
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}”);
抛出新异常($“{keys}已存在。”);
}
var modifiedEntries=ChangeTracker.Entries()
其中(x=>(x.Entity为品牌)和&x.State==EntityState.Modified);
if(modifiedEntry.Any())
{
返回;
}
////待办事项:修改条目的rest代码,比添加的部分更复杂。
}
}

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.
    }
}
公共类示例
{
[键,列(顺序=0)]
公共int Col1{get;set;}
[键,列(顺序=1)]
公共int Col2{get;set;}
[键,列(顺序=2)]
公共int Col3{get;set;}
公共字符串数据{get;set;}
}
公共类MyDbContext:DbContext
{
公共虚拟数据库集示例{get;set;}
公共覆盖int SaveChanges()
{
验证属性();
返回base.SaveChanges();
}
私有void ValidateEntities()
{
var hasChanges=ChangeTracker.Entries()
.Any(x=>(x.Entity为示例)和&(x.State==EntityState.Added | | x.State==EntityState.Modified));
如果(!hasChanges)
{
返回;
}
var addedEntries=ChangeTracker.Entries()
其中(x=>(以x.Entity为例)&&x.State==EntityState.Added)
.选择(x=>x.实体作为示例);
//棘手的问题就在这里:this.Examples.Where(…),它是在DB中执行还是在本地执行?
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}”);
抛出新异常($“{keys}已存在。”);
}
var modifiedEntries=ChangeTracker.Entries()
其中(x=>(x.Entity为品牌)和&x.State==EntityState.Modified);
if(modifiedEntry.Any())
{
返回;
}
////待办事项:修改条目的rest代码,比添加的部分更复杂。
}
}

感谢您快速简洁的回答!对我来说有道理。不幸的是,Any对db.MyTable不可用-我只获得AnyAsync。我对wait db.MyTable.AnyAsync进行了更改,并将我正在编写的方法改为“async”。当我运行时,程序在AnyAsync退出,不会抛出异常。是的,这是正确的答案。在我上面的评论中。任何都没有显示在intellisense中,因为我没有使用System.Linq!!真烦人。对这个解决方案的一个重要修正。db.MyTable.Any仅在接受的行中查找。如果在调用SaveChanges之前搜索数据库集,则需要使用db.MyTable.Local.Any查找已添加但未保存的行。感谢您快速简洁的回答!对我来说有道理。不幸的是,Any对db.MyTable不可用-我只获得AnyAsync。我对wait db.MyTable.AnyAsync进行了更改,并将我正在编写的方法改为“async”。当我运行时,程序在AnyAsync退出,没有异常