检查对象是否存在于Entity Framework中的最佳方法?


Answers:


228

如果您不想直接执行SQL,最好的方法是使用Any()。这是因为Any()一旦找到匹配项就会返回。另一个选项是Count(),但这可能需要在返回之前检查每一行。

这是一个使用方法的例子:

if (context.MyEntity.Any(o => o.Id == idToMatch))
{
    // Match!
}

并在vb.net中

If context.MyEntity.Any(function(o) o.Id = idToMatch) Then
    ' Match!
End If

在VB中如果(context.MyEntity.Any(o => o.Id <> idToMAtch))然后'这是一个匹配项!结束如果抱歉,这不在代码标签中,我不知道该怎么做!
凯文·莫里西

认为您的意思是o.Id <> idToMatch不等于匹配项
Colin

如果我按名称搜索并且想要获取ID(如果存在)怎么办?
Mihai Bratulescu 2014年

你好 我们如何检查它是否存在,然后选择所有数据?
virtouso 2015年

1
@barnes如果限制T为,IEnumerable并返回包含的对象,则Id应该可以使用通用函数IsExists<T>()
Suncat2000


5

我必须处理一个场景,在该场景中,新数据记录中提供的重复项百分比很高,并且要进行数千次数据库调用以检查重复项(因此CPU以100%的时间发送了大量时间)。最后,我决定将最后的100,000条记录保留在内存中。这样,我可以检查缓存记录的重复项,这与对SQL数据库的LINQ查询相比是非常快的,然后将任何真正新的记录写入数据库(以及将它们添加到数据缓存中,我也排序和修剪以使其长度易于管理)。

请注意,原始数据是CSV文件,其中包含许多必须解析的单个记录。每个连续文件中的记录(每5分钟大约有1个记录)重叠很多,因此重复项的百分比很高。

简而言之,如果您给原始数据打了时间戳,几乎是按顺序进行的,那么使用内存缓存可能有助于记录重复检查。


2
很多时候我们的开发人员会提出您的方案,可能会有些曲折。我想请您将您的解决方案翻译成C#,以便我们和许多新的开发人员都能从中受益。+1。我也希望解决方案可以扩展到博客文章!:)
sangam

3

我知道这是一个非常老的线程,但是以防万一像我这样的人需要此解决方案,但是在VB.NET中,这是我根据上述答案使用的。

Private Function ValidateUniquePayroll(PropertyToCheck As String) As Boolean
    // Return true if Username is Unique
    Dim rtnValue = False
    Dim context = New CPMModel.CPMEntities
    If (context.Employees.Any()) Then ' Check if there are "any" records in the Employee table
        Dim employee = From c In context.Employees Select c.PayrollNumber ' Select just the PayrollNumber column to work with
        For Each item As Object In employee ' Loop through each employee in the Employees entity
            If (item = PropertyToCheck) Then ' Check if PayrollNumber in current row matches PropertyToCheck
                // Found a match, throw exception and return False
                rtnValue = False
                Exit For
            Else
                // No matches, return True (Unique)
                rtnValue = True
            End If
        Next
    Else
        // The is currently no employees in the person entity so return True (Unqiue)
        rtnValue = True
    End If
    Return rtnValue
End Function

我不知道如何在VB中使用Lambda,但是在C#中是等效的:return!context.Employees.Any(c => c.PayrollNumber == PropertyToCheck)。这样可以避免返回所有结果然后在内存中循环。
Colin 2013年

1
@Colin这是一个很好的补充,我忽略了以上代码的内存问题,在VB中,代码为context.Employees.Any(c => c.PayrollNumber <> PropertyToCheck)。我现在已经将此添加到我的代码中。
凯文·莫里西

凯文(Kevin),我认为您可能必须回过头来修改您的代码。如果有不匹配的工资单编号,您的逻辑肯定会返回true,而不是在没有匹配的工资单编号时返回true。
Colin 2013年

@Colin对不起,您是对的,我只是为您的示例提供了VB版本,我对C#的使用不多,并认为==不等于我的VB <>。
凯文·莫里西

1
@KevinMorrissey我认为coling表示您需要在“上下文”前面加上“ Not”。由于“返回Not context.Employees.Any(C => c.PayrollNumber = PropertyToCheck)” IS NOT(I重复),IS NOT同为“返回context.Employees.Any(C <> c.PayrollNumber = PropertyToCheck)” 。你明白我的意思吗?使用“返回任何<>”意味着,如果找到与该数字不匹配的任何数字(即使存在匹配的数字),则无论如何都将返回true。而是使用“ Not [...]。Any =”仅在找不到要查找的行时才返回True!你看得到差别吗?
Erx_VB.NExT.Coder 2013年

2

我对此遇到了一些麻烦-我的EntityKey由三个属性(带有3列的PK)组成,并且我不想检查每个列,因为这很丑陋。我想到了一个始终与所有实体配合使用的解决方案。

另一个原因是我不想每次都捕获UpdateExceptions。

需要一点反射来获取关键属性的值。

该代码被实现为扩展,以简化用法,例如:

context.EntityExists<MyEntityType>(item);

看一看:

public static bool EntityExists<T>(this ObjectContext context, T entity)
        where T : EntityObject
    {
        object value;
        var entityKeyValues = new List<KeyValuePair<string, object>>();
        var objectSet = context.CreateObjectSet<T>().EntitySet;
        foreach (var member in objectSet.ElementType.KeyMembers)
        {
            var info = entity.GetType().GetProperty(member.Name);
            var tempValue = info.GetValue(entity, null);
            var pair = new KeyValuePair<string, object>(member.Name, tempValue);
            entityKeyValues.Add(pair);
        }
        var key = new EntityKey(objectSet.EntityContainer.Name + "." + objectSet.Name, entityKeyValues);
        if (context.TryGetObjectByKey(key, out value))
        {
            return value != null;
        }
        return false;
    }

1
我想在我的答案中添加一条评论,该评论已经将近9年了。我认为与Entity Framwork 4相比,如今存在比2010/2011年更清洁的解决方案和可能性。因此,我建议停止对此答案进行投票,而在下面添加一个新的更好的答案。
Sven

还请记住,我的解决方案是一种通用解决方案,适用于具有无法更改的现有表/实体的组合键的许多实体。因此,我不总是使用3个关键属性来查询.Any(...),而是直接调用.EntityExists()。
Sven

2

我只是检查object是否为null,对我来说100%有效

    try
    {
        var ID = Convert.ToInt32(Request.Params["ID"]);
        var Cert = (from cert in db.TblCompCertUploads where cert.CertID == ID select cert).FirstOrDefault();
        if (Cert != null)
        {
            db.TblCompCertUploads.DeleteObject(Cert);
            db.SaveChanges();
            ViewBag.Msg = "Deleted Successfully";
        }
        else
        {
            ViewBag.Msg = "Not Found !!";
        }                           
    }
    catch
    {
        ViewBag.Msg = "Something Went wrong";
    }

0

为什么不这样做呢?

var result= ctx.table.Where(x => x.UserName == "Value").FirstOrDefault();

if(result?.field == value)
{
  // Match!
}

这将引发null引用异常,因为FirstOrDefault()如果找不到结果,将返回null。我猜你可以做if(result?.field == value)来避免这种情况。
ToDevAndBeyond

这可能会不必要地变慢,因为它会加载实体。如果您只想检查密钥是否存在。
道格拉斯·加斯凯尔

0

最好的方法

无论对象是什么以及数据库中的表是什么,您唯一需要拥有的就是对象的主键。

C#代码

var dbValue = EntityObject.Entry(obj).GetDatabaseValues();
if (dbValue == null)
{
   Don't exist
}

VB.NET代码

Dim dbValue = EntityObject.Entry(obj).GetDatabaseValues()
If dbValue Is Nothing Then
   Don't exist
End If

为什么有两个几乎完全相同的答案?差别不大。而且,这当然不是最好的方法。仅从数据库中提取al值只是为了检查记录是否存在是没有意义的。
Gert Arnold
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.