【问题标题】:Best way to check if object exists in Entity Framework? [closed]检查实体框架中是否存在对象的最佳方法? [关闭]
【发布时间】:2010-12-20 14:41:06
【问题描述】:

从性能角度检查数据库中是否存在对象的最佳方法是什么?我正在使用实体框架 1.0 (ASP.NET 3.5 SP1)。

【问题讨论】:

    标签: entity-framework linq-to-entities exists


    【解决方案1】:

    如果不想直接执行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
    

    【讨论】:

    • And in VB If (context.MyEntity.Any(o => o.Id idToMAtch)) Then ' 这是一个匹配!结束 如果对不起,这不在代码标签中,我不知道该怎么做!
    • 认为你的意思是 o.Id idToMatch 不等于匹配
    • 如果我按名称搜索并想获取 ID(如果存在)怎么办?
    • 嗨。我们如何检查它是否存在,然后选择它的所有数据?
    • @barnes 如果您将T 约束为IEnumerable 的接口并返回包含Id 的对象,您应该能够使用您的通用函数IsExists<T>()
    【解决方案2】:

    从性能的角度来看,我想使用EXISTS 命令的直接SQL 查询是合适的。关于如何在 Entity Framework 中直接执行 SQL,请参见此处:http://blogs.microsoft.co.il/blogs/gilf/archive/2009/11/25/execute-t-sql-statements-in-entity-framework-4.aspx

    【讨论】:

    • 是的,好主意,但仅限于以前版本的实体框架。
    【解决方案3】:

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

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

    简而言之,如果您有带时间戳的原始数据按顺序传入,那么使用内存缓存可能有助于记录重复检查。

    【讨论】:

    • 很多时候,我们开发人员提出您的方案,可能会有一些曲折。我想请您用 C# 翻译您的解决方案,以便我们和许多即将到来的开发人员受益。 +1。我也希望将解决方案扩展到博客文章! :)
    【解决方案4】:

    我知道这是一个非常古老的线程,但只是以防像我这样的人需要这个解决方案,但在 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 这是一个很好的补充 我忽略了上面代码的内存问题,在 VB 中代码是 context.Employees.Any(c => c.PayrollNumber PropertyToCheck)。我现在已将此添加到我的代码中。
    • Kevin,我认为您可能需要返回并修复您的代码。如果有任何工资单号码不匹配,您的逻辑肯定会返回 true,而不是在没有任何匹配的工资单号码时返回 true。
    • @Colin 对不起,你是对的,我为你的例子提供了一个 VB 版本,只是我不太正确 C# 并且认为 == 不等于因此我的 VB 。
    • @KevinMorrissey 我认为 coling 是说你需要在“上下文”前面加上“不”。因为“return Not context.Employees.Any(c => c.PayrollNumber = PropertyToCheck)”不是(我重复一遍),IS NOT 与“return context.雇员.Any(c c.PayrollNumber = PropertyToCheck)"。你明白我的意思吗?使用“return Any ”意味着如果您发现任何与此数字不匹配的数字(即使存在匹配的数字),无论如何都将返回 true。相反,使用 "Not [...].Any =" 只会在找不到您要查找的行时返回 True!你看出区别了吗?
    【解决方案5】:

    我遇到了一些麻烦 - 我的 EntityKey 包含三个属性(PK 与 3 列),我不想检查每一列,因为那会很难看。 我想到了一个适用于所有实体的解决方案。

    另一个原因是我不喜欢每次都捕获 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;
        }
    

    【讨论】:

    • 我想在我的回答中添加一条评论,现在我已经快 9 年了。我认为现在有比 2010/2011 年的 Entity Framwork 4 更清洁的解决方案和可能性。所以我建议停止对这个答案投反对票,而是在下面添加一个新的/更好的答案。
    • 还请记住,我的解决方案是一个通用的解决方案,适用于许多具有我无法更改的现有表/实体的复合键的实体。因此,我不再使用 3 个关键属性查询 .Any(...),而是简单地调用了 .EntityExists()。
    【解决方案6】:

    我只是检查 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";
        }
    

    【讨论】:

      【解决方案7】:

      为什么不这样做?

      var result= ctx.table.Where(x => x.UserName == "Value").FirstOrDefault();
      
      if(result?.field == value)
      {
        // Match!
      }
      

      【讨论】:

      • 这将抛出一个空引用异常,因为如果 FirstOrDefault() 找不到结果,它将返回空值。我想你可以做 if(result?.field == value) 来避免这种情况。
      • 这可能会非常慢,因为它会加载实体。如果您只想检查密钥是否存在。
      【解决方案8】:

      最好的方法

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

      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
      

      【讨论】:

      • 为什么有两个几乎相同的答案?差异是微不足道的。此外,这当然不是最好的方法。从数据库中提取所有值只是为了检查记录是否存在是没有意义的。
      猜你喜欢
      • 2011-08-26
      • 2011-05-24
      • 2011-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-17
      相关资源
      最近更新 更多