gpt4 book ai didi

c# - 直接从数据库返回 IEnumerable 或之前使用 ToListAsync

转载 作者:太空宇宙 更新时间:2023-11-03 12:00:18 25 4
gpt4 key购买 nike

当直接从数据库向 Controller 提供 IEnumerable 时, Controller 如何工作?哪个代码更正确和最优?让我们假设数据库非常慢并且正在进行其他操作。

这个例子非常简单,所以执行时间可能没有足够的差异,但我正在努力学习最佳实践。

#1

public Task<Application[]> Find(Expression<Func<Application, bool>> predicate)
{
return DatabaseContext.Applications
.Where(predicate)
.ToArrayAsync();
}

...

public Task<Application[]> Find(...)
{
return ApplicationService.Find(...);
}

#2

public Task<List<Application>> Find(Expression<Func<Application, bool>> predicate)
{
return DatabaseContext.Applications
.Where(predicate)
.ToListAsync();
}

...

public async Task<IActionResult> Find(...)
{
var applications = await ApplicationService.Find(...)
return Ok(applications);
}

#3

public IEnumerable<Application> Find(Expression<Func<Application, bool>> predicate)
{
return DatabaseContext.Applications;
}

...

public IActionResult<IEnumerable<Application>> Find(...)
{
var applications = ApplicationService.Find(...);
return Ok(applications);
}

最佳答案

How do the controllers work when giving them IEnumerable straight from the database?

(通过 IEnumerable 我假设你的意思是直接从你的 IQueryable 返回一个未执行的 DbContext )

他们不会,你也不应该 - 这是因为未执行的 IQueryable不代表加载的数据 - 执行时它只能从打开的数据库连接加载数据 - 这需要有效且有效的 DbContext .

...所以如果 DbContext被处置,那么IQueryable无法执行。

如果您创建 DbContext在 Controller Action 中渲染 IQueryable在您看来或在 ObjectResponse 中返回(对于 Web API)那么它总是会失败:

public IActionResult GetPeople()
{
// WARNING: NEVER DO THIS!
using( MyDbContext db = new MyDbContext( GetConnectionString() ) )
{
return this.Ok( db.People.Where( p => p.Name == "John Smith" ) );

// or:

return this.View( model: db.People.Where( p => p.Name == "John Smith" ) );
}
}

记住 .Ok()this.View()不会触发 View 的评估或向客户端发送对象响应 - 相反,它会导致 Controller 操作先结束,然后将数据传递到 ASP.NET 管道(即 View )中的下一步。请记住: View 在 Controller 操作完成后执行。

如果你使用依赖注入(inject)来获得你的 DbContext 的现成实例在 Controller 中,结果更难预测:IQueryable因为 DbContext 仍然可以在 action 方法返回后进行评估直到 Controller 被释放之后才会被释放,这通常是 呈现 View 之后,但是你仍然不应该这样做,因为你的 IQueryable仍然可以传递给某个超过 Controller 类生命周期的进程,这将导致失败。您还应该避免它,因为 View 旨在快速同步呈现 - 外部数据库或 IO 调用会破坏该设计。

(无论如何,您都不应该将 Entity Framework 实体对象用作根 ViewModel,但那是另一个讨论)。

如果你总是使用 async 就可以避免这个习惯。在 DbContext 上的操作(例如 ToListAsync()ToDictionaryAsync 等 - 因为它们分别返回 Task<List<T>>TaskDictionary<TKey,TValue>> - 这需要一个 await 编译器默认情况下会阻止您在 View 或对象结果中执行此操作(您 < em>可以在 View 中有 await,但这是不可取的,需要在某处设置一些设置。

简而言之,总是这样做:

public async Task<IActionResult> GetPeople()
{
using( MyDbContext db = new MyDbContext( GetConnectionString() ) )
{
List<Person> list = await db.People
.Where( p => p.Name == "John Smith" )
.ToListAsync();

// WebAPI:
return this.Ok( list ); // returning an evaluated list, loaded into memory. (Make sure Lazy Navigation Properties are disabled too)

// MVC:
PeopleListViewModel vm = new PeopleListViewModel(); // in MVC always use a custom class for root view-models so you're not accepting nor returning Entity Framework entity types directly
vm.List = list;

return this.View( vm );
}
}

关于c# - 直接从数据库返回 IEnumerable 或之前使用 ToListAsync,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57368780/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com