实体框架 - 在使用它们之前检查单个记录的正确方法

Posted

技术标签:

【中文标题】实体框架 - 在使用它们之前检查单个记录的正确方法【英文标题】:Entity Framework - Correct way to check for single records before using them 【发布时间】:2010-01-26 20:59:50 【问题描述】:

为了获得记录列表,我通常会按照以下方式进行操作:

var efCompany = from a in _dbRiv.Company where a.CompanyId == companyFeedInfo.CompanyId select a;

要获取单个记录,当我知道我正在使用 PK 来检索它时,我会使用以下内容:

var efCompany = (from a in _dbRiv.Company where a.CompanyId == companyFeedInfo.CompanyId select a).First();

现在,使用单记录方法,如果 PK 是错误值(就像它故意在测试中一样),第二行会引发错误。

获取单个记录并处理它的最佳实践方法是什么?

【问题讨论】:

【参考方案1】:

如果您期望 0 或 1,请使用 SingleOrDefault,或者如果您只需要可能的许多记录中的第一条记录,但可以处理 0,请使用 FirstOrDefault。如果满足以下条件,两者都将返回该类型的默认值(通常为 null)没有结果。

顺便说一句,像这样的查询通常更易读(IMO)没有使用查询表达式,所以你可能有类似的东西:

var efCompany = _dbRiv.Company
                      .Where(a => a.CompanyId == companyFeedInfo.CompanyId)
                      .SingleOrDefault();

if (efCompany != null)

    // Use it

else

    // Report to user, or whatever

当您使用多个运算符或执行相对复杂的操作(如连接)时,查询表达式非常有用 - 但如果您只是有一个where 子句或只是 有一个投影,这个“点符号”更简单 IMO。当您需要在最后调用FirstOrDefault 之类的方法时,它也可以更好地工作。

【讨论】:

感谢您对查询表达式的补充评论。仍然在 EF 上学到了很多东西,我的想法并没有完全围绕 lambda 语法。让我想起了很多旧的 C 内存指针。 ;) SingleOrDefault 在 EF 4 中受支持,但在 EF 1 中不支持。FirstOrDefault 在两者中均受支持。 @Jon Skeet - 将订单后备词放在 LINQ 链上有什么区别......例如。 _db.MyModels.Where(a => a.Prop == "value").SingleOrDefault();_db.MyModels.SingleOrDefault().Where(a => a.Prop == "value"); - 性能?执行令?等等…… @one.beat.consumer:第二个甚至不会编译(通常),因为 SingleOrDefault 返回单个值,而不是序列。但如果它确实 编译,它就不会做你想做的事。它会检查整个 MyModels 表中是否只有一个值,然后对其应用过滤器。 @JonSkeet 我在输入之后就意识到了这一点。这个怎么样:_db.Models.Select(model => new ViewModel Prop = model.Prop ).ToList().Where(viewModel => viewModel.Prop = "value");_db.Models.Select(model => new ViewModel Prop = model.Prop ).Where(viewModel => viewModel.Prop = "value").ToList(); - 这些不同的含义是什么?任何性能差异?数据库活动?选角问题?只是好奇【参考方案2】:

请注意,SingleOrDefault()FirstOrDefault() 都不允许您指定默认值。

DefaultIfEmpty(),它允许您指定如果枚举中没有项目时要返回的默认值。您可以将它与First()(如DefaultIfEmpty().First())结合使用,以实现FirstOrDefault() 类似的行为,并使用lambda 来包装创建一个新实例并将其添加到集合中。

如果只需要检查记录是否存在,也可以使用Any()。但是,如果您需要处理记录(如果存在),这将导致两次查询。

【讨论】:

如果您只需要检查是否存在,Any() 是最好的方法。 DefaultIfEmptySingleOrDefault 一样,在 EF 4 中受支持,但在 EF 1 中不受支持。 我知道这已经 8 岁了,但有没有机会举个例子? @Cloud 抱歉,我在过去七年左右没有接触过任何微软技术,所以... :-/ if (yourDataTable.Any()) if (yourDataTable.Any(x => x.Field == True || x.OtherField == "Test") @Cloud 是这个你想要的例子?【参考方案3】:
var efCompany = _dbRiv.Company
                  .SingleOrDefault(a => a.CompanyId == companyFeedInfo.CompanyId);

if (efCompany != null)

    // Use it

else

    // Report to user, or whatever

【讨论】:

【参考方案4】:

你也可以使用

_dbRiv.Company.find(#id) 

如果您正在寻找没有包含模型的记录。

或者

_dbRiv.Company.FirstOrDefault(x => x.Id == #id);

考虑到性能,我推荐 FirstOrDefault 而不是 SingleOrDefault。使用 SingleOrDefault 它需要扫描整个表并确保只有一条带有 Id 的记录。使用 FirstOrDefault 它可以简单地运行,直到找到该 id 然后停止。在大表上,每次查询都会为您节省少量时间。

如果您不需要跟踪对模型所做的任何更改,您还可以使用 AsNoTracking 来改善内存消耗。例如,如果您通过休息请求返回它而不调用保存。

【讨论】:

我猜如果有索引就不需要扫描整个表了。

以上是关于实体框架 - 在使用它们之前检查单个记录的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQl 正确锁定新实体的创建

实体框架核心存储库模式 - 重复检查

在实体框架中批量插入后批量插入记录并获取它们的 ID

使用实体框架 4.1 代码优先方法将一对一的表关系映射到单个实体

记录实体框架存储过程调用和参数

如何在实体框架中循环创建和删除记录