我需要使用实体框架检查数据库中是否已存在代码客户。理想情况下,我会像这样编写简单的 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 在整个项目中一致使用。
由于您的代码忽略实际 ID,并且仅返回其存在的
true
/false
指示,因此您可以通过一次调用 Any
来完成此操作:
return context.Customers.Any(c => c.RecActive && c.Code == customerCode);
如果您只想检查是否存在,请使用
.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,而不抛出异常。 SingleOrDefault()
。例如:
return context.Customers.Where(c => c.RecActive && c.Code == customerCode)
.Select(c => c.id)
.SingleOrDefault();
为了检查具有复合 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);