Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用ToList()和.AsQueryable()连接两个不同的DB上下文有什么区别?_C#_Sql_Linq - Fatal编程技术网

C# 使用ToList()和.AsQueryable()连接两个不同的DB上下文有什么区别?

C# 使用ToList()和.AsQueryable()连接两个不同的DB上下文有什么区别?,c#,sql,linq,C#,Sql,Linq,案例1: 在这两个上下文中,我通过ToList()方法连接了两个不同的DB上下文 案例2: 还尝试将第一个Db上下文与ToList()连接,第二个与AsQueryable()连接 两个人都为我工作。我只想知道这些连接在性能和功能上的区别。哪一个更好 var users = (from usr in dbContext.User.AsNoTracking() select new {

案例1: 在这两个上下文中,我通过
ToList()
方法连接了两个不同的DB上下文

案例2: 还尝试将第一个Db上下文与
ToList()
连接,第二个与
AsQueryable()
连接

两个人都为我工作。我只想知道这些连接在性能和功能上的区别。哪一个更好

var users = (from usr in dbContext.User.AsNoTracking()
                  select new
                  {
                     usr.UserId,
                     usr.UserName
                  }).ToList();

 var logInfo= (from log in dbContext1.LogInfo.AsNoTracking()
               select new
               {
                   log.UserId,
                   log.LogInformation
               }).AsQueryable();

 var finalQuery= (from usr in users
                  join log in logInfo on usr.UserId equals log.UserId
                  select new
                  {
                     usr.UserName,
                     log.LogInformation
                  }.ToList();

我将详细说明杰霍夫在评论中给出的答案。确实,此联接将在内存中执行。这有两个原因

首先,无法在数据库中执行此联接,因为您正在使用延迟查询(
logInfo
)联接内存中的对象(
users
)。基于此,不可能生成可以发送到数据库的查询。这意味着在执行实际连接之前,将执行一个延迟查询,并从数据库检索所有日志。总之,在这个场景中,2个查询在数据库中执行,连接在内存中发生在这种情况下,使用ToList+AsQueryable或ToList+ToList并不重要。

其次,在您的场景中,这种连接只能在内存中执行。即使将
AsQueryable
与第一个上下文和第二个上下文一起使用,它也不会起作用。您将获得
System.NotSupportedException
异常,并显示以下消息:

指定的LINQ表达式包含对与不同上下文关联的查询的引用

我想知道你为什么要使用2db上下文。真的需要吗?正如我所解释的那样,您失去了充分利用延迟查询(惰性评估特性)的可能性

如果您真的必须使用2个DB上下文,我会考虑添加一些过滤器(其中条件)来查询负责从DB读取用户和日志的查询。为什么?对于少量记录,没有问题。但是,对于大量数据,在内存中执行联接是不高效的。为此目的,创建了数据库。

ToList()

  • 立即执行查询
  • 您将在内存中准备好所有元素
AsQueryable()

  • 懒惰(稍后执行查询)
  • 参数:
    表达式
  • 将表达式转换为T-SQL(使用特定的提供程序),远程查询并将结果加载到应用程序内存中
  • 这就是为什么DbSet(在实体框架中)也继承IQueryable以获得高效查询
  • 它不会加载所有记录。例如,如果采用(5),它将在后台生成select top 5*SQL

还没有解释为什么这些语句实际上可以工作,为什么EF不会抛出一个异常,即您只能在LINQ语句中使用基元类型序列

如果您交换两个列表

var finalQuery= (from log in logInfo
                 join usr in users on log.UserId equals usr.UserId
                 ...
EF将抛出

无法创建“用户”类型的常量值。在此上下文中仅支持基元类型或枚举类型

那么为什么你的代码可以工作呢

如果我们将您的语句转换为方法语法(运行时在后台执行此操作),这一点就会变得很清楚:

由于
users
是一个
IEnumerable
,因此扩展方法被解析为合适的方法。此方法接受一个
IEnumerable
作为要联接的第二个列表。因此,
logInfo
被隐式转换为
IEnumerable
,因此它在参与联接之前作为单独的SQL语句运行

在登录logInfo加入usr的版本中使用…。现在
usr
被转换为
IQueryable
。这会将整个语句转换为一个表达式,EF试图将该表达式转换为一个SQL语句,但未成功

现在请讲几句

哪一个更好

最好的选择是做得足够好的选择。也就是说

  • 您可以删除
    AsQueryable()
    ,因为
    logInfo
    已经是一个
    IQueryable
    并且它被强制转换为
    IEnumerable
  • 您可以将
    ToList()
    替换为
    AsEnumerable()
    ,因为
    ToList()
    构建了一个冗余的中间结果,而
    AsEnumerable()
    只更改
    用户的运行时类型,而不触发其执行

我认为这种连接将“在内存中”发生,但我不确定。因此,用户和登录信息将被读入内存并加入其中。您应该在LinqPad中尝试相同的测试,这将显示生成的SQL的差异。感谢您的响应:)。我怀疑,在案例2中,类型在加入后不会改变。但它仍然是可查询的()@Arthik那么?在内存列表中有一个
IQueryable
是非常好的。请注意,您可以同样轻松地使用
.ToList().AsQueryable()
——结果是列表中的一个可查询项。但是你仍然必须首先得到整个列表:)@Arthik你是对的,logInfo的类型在加入后不会改变。在C#中,在声明变量类型后不能更改它。logInfo被“转换”为场景后面的列表,此操作的结果不会存储在代码中的任何变量中。@Michal,“场景后面”的意思是,这是否发生在任何临时内存中?内存保存列表的时间有多长?@Arthik它出现在应用程序使用的内存(RAM)中。当不再使用此列表时,即没有指向此列表的引用时,垃圾回收会将其从内存中删除。这并不能回答问题
users.Join(logInfo, usr => usr.UserId, log => log.UserId
            (usr,log) => new
                        {
                            usr.UserName,
                            log.LogInformation
                        }