Linq to sql 通过在Task.Run()中包装linq查询,将linq转换为多线程中的sql

Linq to sql 通过在Task.Run()中包装linq查询,将linq转换为多线程中的sql,linq-to-sql,Linq To Sql,将LINQ2SQL查询包装到Task.Run方法中是否合适,如下所示 var keywordlistquery = await Task.Run(() => { using (DataContext context = new DataContext(connection)) { context.ObjectTrackingEnabled = false; ret

将LINQ2SQL查询包装到Task.Run方法中是否合适,如下所示

var keywordlistquery = await Task.Run(() =>
        {
            using (DataContext context = new DataContext(connection))
            {
                context.ObjectTrackingEnabled = false;
                return from keyword in context.GetTable<KeywordsList>()
                       select new
                       {
                           keyword.search_text,
                           keyword.search_keyword
                       };
            }
        });
var关键字列表查询=等待任务。运行(()=>
{
使用(DataContext上下文=新DataContext(连接))
{
context.ObjectTrackingEnabled=false;
从context.GetTable()中的关键字返回
选择新的
{
关键字.search\u文本,
关键字.search\u关键字
};
}
});

上述代码是线程安全的吗?在生产过程中是否会出现任何问题。是否有其他更好的方法编写上述代码。

这里的好答案很大程度上取决于代码的意图

但一般来说,请记住,Linq-to-SQL技术是在.Net中实现本机异步和等待模式之前构建并停止的

因此,除非您非常习惯手动维护异步任务,否则最好不要尝试将异步与LINQtoSQL结合使用。很有可能,除非期望服务器处理非常高级别的请求并发性,否则性能不会有多大提高,但是手动处理异步任务是引入真正难以检测的错误的一种非常好的方法,这些错误最终会意外地阻塞请求线程

如果您确实需要在这样的代码中处理异步,有两种解决方案

首先要理解上面的代码创建了一个查询,但没有执行它。它返回的是一个可解的。。。基本上,可以将其视为尚未运行的SQL语句。在调用ToArray或ToList之类的方法之前,或者在foreach循环或类似循环中使用该方法之前,LINQtoSQL不会运行查询

此外,当您使用return语句时,处理这样的匿名类型也变得很困难。您可能需要创建DTO类并使用select投影来实例化它们

第二,将上下文包装在using块中(这是一种良好的做法),但是如果在实际执行查询之前返回查询,则上下文将被释放。调用者将获得一个IQueryable,但当它尝试使用它时,您将得到一个异常,因为上下文已被释放

所以。。。。这里有两个选项,这取决于此代码是用于返回实际数据,还是仅返回调用方可以进一步修改的查询

案例1)返回数据:

public async Task<object> DoThings(CancellationToken token)
{
    var keywordlistquery = await Task.Run(() =>
    {
        using (var context = new DataClasses1DataContext())
        {
            context.ObjectTrackingEnabled = false;
            return from keyword in context.GetTable<KeywordsList>()
                    select new
                    {
                        keyword.search_text,
                        keyword.search_keyword
                    };
        }
    }, token);
    return keywordlistquery;
}
公共异步任务点hings(CancellationToken令牌)
{
var关键字ListQuery=等待任务。运行(()=>
{
使用(var context=new DataClasses1DataContext())
{
context.ObjectTrackingEnabled=false;
从context.GetTable()中的关键字返回
选择新的
{
关键字.search\u文本,
关键字.search\u关键字
};
}
},代币);
返回关键字列表查询;
}
请注意,方法本身应该是异步的,如果可能,您应该始终尝试使用取消令牌。这将调用ToArray强制现在执行查询并返回数据。请记住,这将返回整个表。如果调用方希望提供where子句或其他什么,代码仍将加载所有数据

案例2:可恢复的返回

在案例2中,您希望方法只返回查询。这样,调用方可以在执行查询之前修改查询。这允许调用者添加语句以包括where子句或对结果排序或其他内容;并将这些语句包含在生成的TSQL中

在这种情况下,诀窍在于调用方必须控制数据上下文的生命周期,并且由于该方法没有实际执行结果,因此不需要是异步的

public async Task CallingMethod()
{
    using (var context = new DataClasses1DataContext())
    {
        var token = new CancellationToken();
        context.ObjectTrackingEnabled = false;
        var query = DoThings(context);
        var result = await Task.Run(() => query.ToArray(),  token);
    }
}

public IQueryable<object> DoThings(DataContext context)
{
    var keywordlistquery = from keyword in context.GetTable<KeywordsList>()
        select new
        {
            keyword.search_text,
            keyword.search_keyword
        };
    return keywordlistquery;
}
公共异步任务调用方法()
{
使用(var context=new DataClasses1DataContext())
{
var token=新的CancellationToken();
context.ObjectTrackingEnabled=false;
var query=DoThings(上下文);
var result=wait Task.Run(()=>query.ToArray(),token);
}
}
公共IQueryable点hings(DataContext上下文)
{
var keywordlistquery=from context.GetTable()中的关键字
选择新的
{
关键字.search\u文本,
关键字.search\u关键字
};
返回关键字列表查询;
}

正如我之前提到的,select new ANONYOUS在这种情况下不起作用。最好创建一个DTO类并从中选择一个新类,或者返回整个表

这将不起作用,因为您返回的是可查询项,而不是结果。当您尝试访问结果时,上下文已关闭。无论如何,实体框架总是有异步操作,所以尝试让L2S异步运行没有多大意义。没有比var results=await(from…).ToListAsync()更好的了这是LINQtoSQL代码,因此没有内置任何异步方法。