使用实体框架LINQ高效检查数据库中是否存在记录

问题描述 投票:0回答:3

我需要使用实体框架检查数据库中是否已存在代码客户。理想情况下,我会像这样编写简单的 sql 查询:

select id from dbo.Customer where RecActive = 1 and Code = 'xxx';

如果查询结果为空,则表示code 'xxx'的客户还不存在。在实体框架中,有多种方法可以编写此内容,但我正在寻找上面最接近的一种注意:Code 字段有唯一索引

  using (var context = new CustomerContext())
  {
    // not very efficient as it reads all columns
    return context.Customers.Where(c => c.RecActive && c.Code == customerCode).SingleOrDefault() != null ? true : false;

    return context.Customers.Where(c => c.RecActive && c.Code == customerCode).Count() > 0 ? true : false;

    // translates to this query:
    // exec sp_executesql N'SELECT [Limit1].[Id] AS [Id]
    // FROM ( SELECT TOP (2) 
    //        [Extent1].[Id] AS [Id]
    //        FROM [dbo].[Customer] AS [Extent1]
    //        WHERE ([Extent1].[RecActive] = 1) AND (([Extent1].[Code] = 
    //          @p__linq__0) OR (([Extent1].[Code] IS NULL) AND 
    //          (@p__linq__0 IS NULL)))
    //        )  AS [Limit1]',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'xxx'
    int a = context.Customers.Where(c => c.RecActive && c.Code == customerCode).Select(c => c.Id).SingleOrDefault();             
    return a > 0 ? true : false;

    return context.Customers.Where(c => c.RecActive && c.Code == customerCode).Any();
  }

也许还有其他好的(性能替代方案)?注意:我必须使用实体框架 linq 而不是原始查询(我真的很喜欢),因为 linq 在整个项目中一致使用。

c# entity-framework linq linq-to-sql
3个回答
8
投票

由于您的代码忽略实际 ID,并且仅返回其存在的

true
/
false
指示,因此您可以通过一次调用
Any
来完成此操作:

return context.Customers.Any(c => c.RecActive && c.Code == customerCode);

6
投票

如果您只想检查是否存在,请使用

.Any()
。如果您想检索符合条件的 ID,请使用
Select
,例如:

 context.Customers
        .Where(c => c.RecActive && c.Code == customerCode)
        .Select(c => c.id);

如果多个 ID 是有效结果,则无论

id
的类型是什么,您的方法都应返回字符串/整数数组。您可以使用
.ToArray();

返回 ID 数组
 return context.Customers
               .Where(c => c.RecActive && c.Code == customerCode)
               .Select(c => c.id)
               .ToArray();

如果您期望有多个ID,则必须决定在获得多个结果时该怎么办:

    如果有多个结果,
  • FirstOrDefault()
    将返回第一个ID,而不抛出异常。
  • 如果有多个结果阻止使用可能无效的 ID,则会抛出
  • SingleOrDefault()

例如:

return context.Customers.Where(c => c.RecActive && c.Code == customerCode)
               .Select(c => c.id)
               .SingleOrDefault();

0
投票

为了检查具有复合 PK 的多个实体的存在,我想出了以下方法:

// Returns the subset of entities that don't exist in the db.
private IReadOnlyList<TEntity> GetNewEntities<TEntity>(
    IEnumerable<TEntity> entities,
    Func<TEntity, Expression<Func<TEntity, bool>>> getPredicate) where TEntity : class
{
    var newEntities = new List<TEntity>();
    foreach (var entitiesBatch in entities.Batch(100))
    {
        var entitiesExistence = GetEntitiesExistence(entitiesBatch, getPredicate);
        newEntities.AddRange(entitiesBatch
            .Where((_, i) => !entitiesExistence[i]));
    }

    return newEntities;
}

private IReadOnlyList<bool> GetEntitiesExistence<T>(IEnumerable<T> entities, Func<T, Expression<Func<T, bool>>> getPredicate) where T : class
{
    IQueryable<bool> query = null;
    var set = this.dataEntities.Set<T>();
    foreach (var entity in entities)
    {
        var tempQuery = set.Where(getPredicate(entity))
            .Select(x => true)
            .DefaultIfEmpty(false);
        query = query == null ? tempQuery : query.Concat(tempQuery);
    }
    return query.ToArray();
}

getPredicate 指定两个实体之间的相等性,它可以是:

e1 => e2 =>
    e1.Key1 == e2.Key1 &&
    e1.Key2 == e2.Key2

对批量大小进行性能实验。 使用示例:

var newUsers = GetNewEntities(users,
    u1 => u2 =>
        u1.FirstName == u2.FirstName &&
        u1.LastName == u2.LastName);
© www.soinside.com 2019 - 2024. All rights reserved.