Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.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# 加速实体框架调用_C#_Entity Framework_Linq_Optimization_Query Optimization - Fatal编程技术网

C# 加速实体框架调用

C# 加速实体框架调用,c#,entity-framework,linq,optimization,query-optimization,C#,Entity Framework,Linq,Optimization,Query Optimization,我有一个API中的数据调用存储库,目前,在测试中,它可以像预期的那样完美地工作,尽管使用更大的数据集时,速度几乎呈指数级下降。我一直在寻找越来越多的方法来尝试提高性能,尽管我似乎找不到太多与包含相关的信息,也找不到使用实体框架加速数据查询的信息 下面是我的一个较慢通话的示例。我想问一下,对于这种查询,有什么更好的方法。我还将包括数据库的关系图,以供参考,以明确其所要求的实体。有什么想法吗 public异步任务getAllClient() { List clientList=(等待santaCon

我有一个API中的数据调用存储库,目前,在测试中,它可以像预期的那样完美地工作,尽管使用更大的数据集时,速度几乎呈指数级下降。我一直在寻找越来越多的方法来尝试提高性能,尽管我似乎找不到太多与包含相关的信息,也找不到使用实体框架加速数据查询的信息

下面是我的一个较慢通话的示例。我想问一下,对于这种查询,有什么更好的方法。我还将包括数据库的关系图,以供参考,以明确其所要求的实体。有什么想法吗

public异步任务getAllClient()
{
List clientList=(等待santaContext.Client
/*调查和答复*/
.包括(c=>c.SurveyResponse)
。然后包括(sr=>sr.SurveyQuestion.SurveyQuestion选项外部参照)
.Then包括(sqox=>sqox.SurveyOption)
.包括(c=>c.SurveyResponse)
。然后包括(sr=>sr.SurveyQuestion.SurveyQuestion外部参照)
.包括(c=>c.SurveyResponse)
.ThenInclude(sr=>sr.Survey.EventType)
/*发送者/分配信息和标签*/
.Include(c=>c.ClientRelationXrefRecipientClient)
.ThenInclude(crxsc=>crxsc.SenderClient.ClientTagXref)
.然后包括(txr=>txr.Tag)
.Include(c=>c.ClientRelationXrefSenderClient)
.Then包括(crxrc=>crxrc.RecipientClient.ClientTagXref)
.然后包括(txr=>txr.Tag)
/*关系事件*/
.Include(c=>c.ClientRelationXrefSenderClient)
.ThenInclude(crxsc=>crxsc.EventType)
.Include(c=>c.ClientRelationXrefRecipientClient)
.ThenInclude(crxrc=>crxrc.EventType)
/*聊天信息*/
.Include(c=>c.ClientRelationXrefRecipientClient)
.然后包括(cm=>cm.ChatMessage)
.Include(c=>c.ClientRelationXrefSenderClient)
.然后包括(cm=>cm.ChatMessage)
/*分配状态*/
.Include(c=>c.ClientRelationXrefRecipientClient)
.ThenClude(stat=>stat.AssignmentStatus)
.Include(c=>c.ClientRelationXrefSenderClient)
.ThenClude(stat=>stat.AssignmentStatus)
/*标签*/
.Include(c=>c.ClientTagXref)
.然后包括(t=>t.Tag)
/*注释*/
.包括(c=>c.注)
/*客户批准状态*/
.Include(c=>c.ClientStatus)
.AsNoTracking()
.ToListAsync())
.Select(Mapper.MapClient.ToList();
返回客户列表;
}

我不认为您在所有情况下都需要所有这些相关实体。所以尽量不要这样做。根据具体情况向存储库添加更多方法

无论如何,EF Core 5有
AsSplitQuery
扩展,它可能会加速这场噩梦,也可能不会

Mapper.MapClient
-尝试使用表达式(在ToList之前选择),您的查询将只获得所需的数据。 如果通过表达式映射对象,甚至根本不需要包含

理想情况下,您的查询应该是这样的(我更喜欢在没有Automapper的情况下手动执行)

它可以通过扩展方法来实现

public static IQueryable<Logic.Objects.Client> ToDto(this IQueryable<Client> query, bool includeQuestions)
{
    if (includeQuestions)
       return query.Select(/* projection with questions */)
    return query.Select(/* projection without questions */)
}
....

await santaContext.Client.ToDto(true).ToListAsync();
public static IQueryable ToDto(此IQueryable查询,bool includeQuestions)
{
如果(包括问题)
返回查询。选择(/*带问题的投影*/)
返回查询。选择(/*无问题投影*/)
}
....
等待santaContext.Client.ToDto(true.tolistSync();

稍后,您会发现您需要方法重用,但这是另一个需要动态修改表达式树的复杂问题。

查询速度慢的原因之一是因为您使用
Include
获取子集合

如果客户端[10]有1000条ChatMessages,则每个ChatMessages都会有一个值为10的外键ClientId。如果您获取“Client[10]with his ChatMessages”,您将发送该值10次以上1000次

此外,如果使用Include获取子项和完整对象,则获取的项也存储在中。 在从DbContext获取完整对象之前,将检查该项是否已在ChangeTracker中,如果不在,则从数据库管理系统查询数据并将其放入ChangeTracker中

使用实体框架时,请始终使用“选择”,并仅选择实际计划使用的属性。仅选择完整对象,并且仅在计划更新获取的数据时使用“包含”

当然,不要使用Include来节省键入的时间

此外,明智的做法是不要在返回中使用原始表行类,而是使用匿名类型,或者如果需要从方法返回,则使用与原始表类似的特殊存储库类

中间存储库类的优势使您可以自由隐藏数据库布局。甚至可以隐藏您正在使用数据库。它可以是XML文件或JSON,也可以是单元测试的字典。因为您断开了表布局与方法用户获得的数据的连接,所以可以使返回的结构与数据库表不同。这将为不同的用户类型启用不同的查询。将来可以在不必更改存储库查询的情况下更改数据库布局

例如,如果您决定添加一个属性
Isobsolite
,那么您可以选择向普通用户提供返回
客户端
而不包含此属性的查询。如果普通用户查询“所有Clie”
public static IQueryable<Logic.Objects.Client> ToDto(this IQueryable<Client> query, bool includeQuestions)
{
    if (includeQuestions)
       return query.Select(/* projection with questions */)
    return query.Select(/* projection without questions */)
}
....

await santaContext.Client.ToDto(true).ToListAsync();
class Student
{
    public int Id {get; set;}
    public string Name {get; set;}
    public string Street {get; set;}
    public string City {get; set;}
    ...
}
class Student
{
    public int Id {get; set;}
    public string Name {get; set;}

    public int AddressId {get; set;}
}
List<Logic.Objects.Client> clientList = (await santaContext.Clients
.Select(client => new Repository.Client()
{
    // only Select the Client properties that you plan to use
    Id = client.Id,
    Name = client.Name,
    ...

    SurveyResponses = client.SurveyReponses.Select(surveryResponse => new Repository.SurveyResponse
    {
         // again: only the properties that you plan to use:
         Id = surveyResponse.Id,
         ...

         // not needed, you already got the value:
         // ClientId = surveyResponse.ClientId,

         Questions = surveyResponse.SurveyQuestions.Select(...).ToList(),
         Responses = surveyReponses...
    })
    .ToList(),

    // similar for Sender / Assignment / Tag / etc
})