2017-08-27 41 views
1

在我的ASP.NET MVC网站中,用户浏览书籍。他们可以选择添加他们自己创建的列表中的每本书。外部DbContext调用期间EF DbContext的内部调用异步行为ASP.NET MVC

当用户浏览一本书时,每本书下面的所有列表都有一个下拉列表,他可以选择添加书籍。迄今为止所有的都很好,但是我现在想要的是,如果该书已经包含在用户列表中的一个列表中,则该下拉列表应该知道。

这是相关视图模型:

public class UserBookListsMinimalVM { 
    public int ListId { get; set; } 
    public string ListName { get; set; } 
    public bool BookAlreadyInList { get; set; } 
} 

这是我跑检索项查询:

var userBookLists = await context.vwUserBookLists 
           .Where(x => x.ListOwner == userName) 
           .Select(x => new UserBookListsMinimalVM 
           { 
            ListId = x.ListId, 
            ListName = x.ListName, 
            BookAlreadyInList = context.List_Books.Any(y => y.ListId == x.ListId && y.BookId == bookId) 
           }) 
           .OrderBy(x => x.ListName) 
           .ToListAsync(); 

vwUserBookLists是包含列表相关的信息和List_Book一个观点是中介列表和书籍之间的表格(包含每个列表的书籍等)。

由EF生成的SQL嵌套SELECT语句,主要是为了解释BookAlreadyInList属性。 (我不知道查询是否可以简化的,我愿意接受建议)

BookAlreadyInList分配“破发”的全功能的异步过程中不调用context,看它是不是await版?

+1

您是否观察到此代码出现任何意外行为?有什么不工作?我不清楚你究竟在问什么。对'.Any()'的调用不需要等待,因为它不是异步的。 – David

+0

嗨@大卫 - 它工作正常(即它返回预期的结果)。我的问题是在'BookAlreadyInList'分配期间对'context'的非异步调用是否与外部'await context'异步调用冲突'。应该.Any()成为'.AnyAsync()'? – globetrotter

+1

我不认为有'.AnyAsync()'(尽管你可以很快测试)。实际上并不需要,因为'.Any()'实际上并未实现数据源中的任何内容。它被转换为支持数据存储的表达式树,就像其他更多的LINQ方法一样。只有实际物化数据的方法(比如'.ToList()')需要异步版本。 – David

回答

2

它不会破坏你的异步操作,当ToListAsync()完成这项工作时它将完成。只有一个异步操作,在此之前不会被任何异常操作破坏,无论您在查询中做什么,都会遵守await /异步合同。即使你试图实现其中的一些实体,例如调用同步的ToList()(假设EF会容忍这个),这个同步调用将在后台线程中进行。您不能在您的查询中使用AnyAsync,因为sql提供程序无法转换异步操作,该操作特定于c#而不是sql server。

这就是说,更重要的是,你仍然可以问自己EF是否只向数据库发送一个查询,或者将你的查询翻译成多个数据库调用(可能是这种情况,这取决于你使用的版本),甚至在内存中进行一些操作。要知道究竟发生了什么,最好的方法是查看输出窗口,看看是否可以看到生成的sql,或者在执行代码时启动观察数据库的sql profiler。 在.net核心的最新版本中,您可以配置您的dbcontext以在表达式树无法完全转换为sql并且必须在内存中执行某些操作时抛出异常。如果您不这样做,您仍会在输出窗口中收到警告。