Entity Framework Core(7):按ID加载单个实体

8

.ToListAsync 用于从 EF Core 中获取一组项。这很清楚。但是,如果可能的话,在异步方式下获得单个项目的正确方法是什么呢?

public async static Task<Source> LoadEntityAsync(int sourceID)
{
    using (var db = new RPDBContext())
    {
        var sources =
            await
                db.Source
                    .Where(x => x.SourceID == sourceID)
                    .ToListAsync();
        // TODO that's like a hack:
        return sources.First();
    }
}

1
使用 Single 而不是 First,因为 First 实际上相当于一个盲目的 try/catch/continue 块。如果有多个结果,则应抛出错误,这正是 Single 所做的。 - Cesar
1
你有没有看到@Liviu Sosu的回答?根据文档,他的回答似乎比被接受的那个更好。 - undefined
1
@EricOuellet,我同意。我已经接受了其他答案,谢谢。 - undefined
3个回答

5

如果你想保证对象的唯一性,应该使用SingleOrDefaultAsync。如果你知道对象是通过域限制保证唯一性或者通过主键访问,那么可以使用FirstOrDefaultAsync

var sources = await db.Source
            .Where(x => x.SourceID == sourceID)
            .SingleOrDefaultAsync();

您可以使用另一个重载并缩短查询。
var sources = await db.Source
            .SingleOrDefaultAsync(x => x.SourceID == sourceID);

FirstOrDefaultAsync适用相同的规则。

如果您想确保对象存在,只需删除OrDefault部分并使用SingleAsyncFirstAsync


1
我在EF Core中找不到Queryable.FooAsync()方法,有点困扰。我需要引用其他的包吗?编辑 算了,我得添加using Microsoft.EntityFrameworkCore; 我猜应该是这样的。不幸的是,EF Core似乎没有发布API文档。 - Homr Zodyssey
1
@Homr Zodyssey,关于“using Microsoft.EntityFrameworkCore;”的好笔记,那些异步操作不是Linq的一部分,而是EFCore的。 - Konstantin

4

2
非常感谢您的澄清。您的回答看起来性能确实更好! - undefined

2

如果您需要检索单个项目,请使用FirstOrDefaultAsync

public static Task<Source> LoadEntityAsync(int sourceID)
{
    using (var db = new RPDBContext())
    {
        return db.Source.FirstOrDefaultAsync(x => x.SourceID == sourceID);
    }
}

1
为什么要使用“First”而不是“Single”?如果有多个,它应该会抛出一个错误,特别是因为您没有任何排序逻辑。您应该使用“SingleOrDefault”。 - Cesar
@Cesar 如果这应该是一个错误,那么它应该由您的关系模型强制执行,而不是由您的查询。 - Kevin Gosse
FirstOrDefault 明确指示模型忽略任何错误,我见过很多开发人员编写这种有缺陷的代码,他们因某种原因害怕出错,这实际上是一个伪装成 try/catch/continue 的逻辑。而且这个逻辑是错误的。如果你想加载一个实体(根据定义是唯一的),那么为什么你的代码要寻找第一个匹配项呢?! - Cesar
@Cesar FirstOrDefault并指示模型忽略错误。它指示上下文仅获取一个实例(SELECT TOP 1 ...)。如果您用于筛选的字段是主键,则数据库保证永远不会有多个实例。因此,无需检查。在给定的示例中,可以合理地假设SourceID确实是Source表的主键。 - pescolino
@pescolino 逻辑恰好相反。由于不应该有任何区别,因此应使用更严格、更正确的方法。一种明确声明应该只有一个的方法。如果有人以某种方式搞乱了数据库中的主键,就会抛出错误,否则它将提供完全相同的性能。采用你的方法只是另一种盲目的捕获/继续。坚持使用 First(为什么不是 Last?)只是固执。我遇到过许多这样的开发人员,他们后来哭泣着谈论随机行为。FirstOrDefault 确实指示代码忽略错误。 - Cesar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接