在插入新记录之前检查记录是否已存在

14
我第一次使用Ado.net实体框架,需要在将记录插入数据库之前检查该记录是否存在。最好是搜索AuthodSSID是否存在,而不是键(AuthorID)。我使用的是VS2010,Framework 4。System.Data.Entity是3.5.0.0。 我已经搜索了,但没有找到此问题的答案。
PublishingCompanyEntities publishContext;
publishContext = new PublishingCompanyEntities();

private void createNew_Click(object sender, EventArgs e)
{
    Author newAuthor = new Author();
    newAuthor.FirstName = firstName.Text;
    newAuthor.LastName = lastName.Text;
    newAuthor.AuthodSSID = 20;
    newAuthor.AuthorID = 10
//Check if record exist here
    publishContext.AddToAuthor(newAuthor);//insert if does not exist

}

1
旧但仍然像DUP;更多信息可以在https://dev59.com/BnI-5IYBdhLWcg3wio9k找到。 - Joel Peltonen
可能是Entity Framework中检查对象是否存在的最佳方法?的重复问题。 - William Ardila
5个回答

22

检查一条记录是否存在的唯一方法是查询该记录并查看是否返回任何内容:

var existingAuthorCount = publishContext.Author.Count(a => a.AuthodSSID == 20);
if (existingAuthorCount == 0) 
{
    // Do your insert
}

1
工作正常,只是需要找出为什么.Count没有出现。很简单,顶部缺少了using System.Linq;!谢谢! - BirdOfPrey
1
从臭名昭著的Eric Lippert的明智建议中得出:你有一个完全装满了便士的罐子。有人问你“罐子里有便士吗?”。你是计算它们然后将答案与零进行比较,还是看看罐子里是否至少有一个便士?(引用)此解决方案的性能将取决于“Author”包含的行数。我已更新我的答案,以仅查找1个结果查询。 - M.Babcock
6
你能否不使用 "publishContext.Author.Any(a => a.AuthodSSID == 20)"这个语句?或者在EF中它无法使用吗? - Trevor Pilley
我想重申Trevor所说的话。我目前正在使用.Any,我认为这是相同的情况。 - mrshickadance
1
如果你的EF版本支持Any,请使用@M.Babcock提供的答案。 - Jacob

12

像这样应该可以工作:

if (publishContext.Author.Select(a => a.AuthodSSID).Where(id => id == 20).Take(1) == null)
    // It doesn't exist
else
    // It does exist

基于我(尽管是基础)的理解,这应该生成一个等价于以下SQL语句的语句:

SELECT TOP(1) AutodSSID FROM Author WHERE AuthodSSID = 20;

另一种更简单的方法可能是使用 Any 扩展方法:

if (!publishContext.Author.Any(a => a.AuthodSSID == 20))
    // Put your insert logic here.

这个方法可以实现,并且如果作者存在,它是最好的更新方法。然而,这将选择所有作者的列,而您可能不需要。按照我的答案进行计数会更有效率。 - Jacob
@Jacob - 计数实际上与包括选择单个列相同,但是使用 SingleOrDefault 我认为它会执行 TOP 1,而 COUNT(*) 仍然需要 所有 记录,或者我错过了什么? - M.Babcock
1
好问题。我对TOP 1的担忧是,所有仍然会返回那一行。COUNT可能需要在数据库上进行更多的表扫描,但只返回一个整数。也许最好的选择是先进行Where,然后选择主键,接着进行Take(1)。这应该解决两个问题。 - Jacob
@Jacob - 就像我的当前回答一样? - M.Babcock
不。您当前的答案返回所有列。 - Jacob

4

从.NET的角度来看,我个人更喜欢这种方法。它更干净,如果你关心速度(在.NET中),它更高效,但是SQL并不那么出色。

private bool CheckIfEntityRecordExists(Entity e)
{
    var retVal = false;
    using (var db = new EntityContext())
    {
        retVal = db.AdviserClients.Any(a => a.Id == e.Id);
    }
    return retVal;
}

因此,对于高效的SQL语句,以下是最佳选择:

private bool CheckIfEntityRecordExists(Entity e)
{
    var retVal = false;
    using (var db = new EntityContext())
    {
        retVal = db.AdviserClients.Count(a => a.Id == e.Id) > 0;
    }
    return retVal;
}

3
虽然我已经为你的答案点赞了,但从性能角度考虑,应该使用db.context.Any()而不是db.context.Count(),因为Count()会迭代所有数据,而Any()只会在第一个匹配项处停止。 - Anshul Nigam
使用 Any 是使用 EF 检查行是否存在于数据库中的最便宜的方法。这是我进行所有此类检查的标准方式。 - Manuel.B

2

此方法建议仅用于迁移以种子数据,而不是作为upsert方法

在EF v5.0+中有所谓的“upsert”操作。

publishContext.Author.AddOrUpdate(x => x.Id, newAuthor)

AddOrUpdate可以在"System.Data.Entity.Migrations"命名空间中找到,所以不要忘记添加:

using System.Data.Entity.Migrations;

AddOrUpdate 操作不是原子操作。但是,*if (existingAuthorCount == 0) {// Do your insert} 也不是。

1
你好 :DDDDDD - Jota.Toledo

0

你所需要做的就是使用 LINQ 搜索具有该 ID 的作者。

Where() 方法将返回一个作者集合,你只需要一个,因此可以使用 FirstOrDefault(),它将返回第一个元素或 null(如果没有元素)。你也可以使用 SinglOrDefault,如果列表中有多个元素,则会引发异常,或者仅返回该元素。

看起来 @Jacob 有一个更优秀、更高效的方法!

var author = publishContext.Authors.Where
                               (a=>a.AuthodSSID == 10).FirstOrDefault();
if(author == null) //none exist
{//don't bother creating one unless you need to..
    Author newAuthor = new Author();
    newAuthor.FirstName = firstName.Text;
    newAuthor.LastName = lastName.Text;
    newAuthor.AuthodSSID = 20;
    newAuthor.AuthorID = 10
    publishContext.AddToAuthor(newAuthor);//insert if does not exist
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接