简体   繁体   中英

How to a List using LINQ Query?

I am trying to return one list, which I got from this query, but getting error:

cannot convert from 'System.Collections.Generic.List<<anonymous type: string DocumentTypeName, int ProcessedDocument, int UnProcessedDocument>>' to 'System.Collections.Generic.IReadOnlyList<HOLMES.DocCognition.VariableLayoutDocument.Dto.DashboardCountDto>' [HOLMES.DocCognition.Application]csharp(CS1503)"

I am new to c# and Linq. Please help to resolve this.

public async Task<ListResultDto<DashboardCountDto>>  CountAllTrainDocuments()
        {
                var retList = new List<DashboardCountDto>();
              var allTrainFiles = await _trainDocumentRepository.GetAllListAsync();
               var CountTrainFiles = allTrainFiles.GroupBy(t=> t.DocumentTypeName).
                                    Select(e => new { 
                                         //count = e.Count(),
                                    DocumentTypeName = e.Key,
             ProcessedDocument = e.Count(g => g.Processed = true),
             UnProcessedDocument = e.Count(g => g.Processed = false),
            
         }).ToList();

            Dictionary<string, int> innerDict = new Dictionary<string, int>();   
            Dictionary<string, string> outterDict = new Dictionary<string, string>(); 
          // return retList;

           CountTrainFiles.ForEach(
             row => Console.WriteLine($"DocType: {row.DocumentTypeName}, ProcessedDocument: {row.ProcessedDocument}, UnProcessedDocument: {row.UnProcessedDocument}"));

      return new ListResultDto<DashboardCountDto>(CountTrainFiles);

My DTO looks like:

public class DashboardCountDto : EntityDto<long>
    {
        public string DocumentTypeName { get; set; }
        public int ProceesedDocumentCount { get; set; }
        
         public int UnProceesedDocumentCount { get; set; }

    }

This:

new 
{
  //count = e.Count(),
  DocumentTypeName = e.Key,
  ProcessedDocument = e.Count(g =>g.Processed = true),
  UnProcessedDocument = e.Count(g =>g.Processed = false),
}

creates an anonymous object that structurally looks like a DashboardCountDto , but isn't a DashboardCountDto . Create a real one instead by using the class name after new :

new DashboardCountDto
{
  //count = e.Count(),
  DocumentTypeName = e.Key,
  ProcessedDocument = e.Count(g =>g.Processed = true),
  UnProcessedDocument = e.Count(g =>g.Processed = false),
}

Short answer:

Change your Selecte(e => new { into Selecte(e => new DashboardCountDto {

That will solve your problem.

Longer answer:

Your query is not very efficient.

Database management systems are extremely optimized to execute database queries. The slower part of a database query is the transfer of the selected data from the DBMS to your local process. Hence you should try to let your DBMS do all processing, and try to limit all transferred data to data that the DBMS can't process anymore.

First you fetch all properties of all train files, and you put them in a list. Then your local process groups the fetched train files into groups of train files that have the same DocumentTypeName. From every Group of train files, you throw away most things, you only count which ones are Processed and which ones aren't.

It would be way more efficient to let the DBMS do that. See if your repository has a method that returns IQueryable<TrainFile> , instead of Task<List<TrainFile>> . If the repository doesn't have it, consider to add it to your repository.

IQueryable<TrainFile> trainFiles = trainDocumentRepository.TrainFiles();

// make groups of TrainFiles with Same documentName and count the number of Processed:
var groups = trainFiles.GroupBy(trainFile => trainFile.DocumentName,

    // Parameter resultSelector: use each DocumentName, and all TrainFiles that have this
    // value of DocumentName to make one new DashboardCountDto
    (documentName, trainFilesWithThisDocumentName) => new DashboardCountDto
    {
        DocumentTypeName = documentTypeName,
        Processed = trainFilesWithThisDocumentName
                    .Where(trainFile => trainFile.Processed)
                    .Count(),
        UnProcessed = trainFilesWithThisDocumentName
                    .Where(trainFile => !trainFile.Processed)
                    .Count(),
    });

Note: each trainFileWithThisDocumentName is scanned twice: once to count the Processed train files, and once to count the unprocessed train files. A sub-GroupBy will solve this problem:

(documentName, trainFilesWithThisDocumentName) => new
{
    DocumentName = documentName,
    SubGroups = trainFilesWithThisDocomentName.GroupBy(trainFile => trainFile.Processed,

         // Parameter resultSelector:
         (processed, trainFilesWithThisValueOfProcessed) => new
         {
             Processed = processed,
             Count = trainFilesWithThisValueOfProcessed.Count(),
         })
         .OrderByAscending(subGroup => subGroup.Processed)
         .ToList(),
    }),

So now you have per DocumentName one object, that contains the DocumentName, and a property SubGroups, which is a list of two objects: one with Process true, and Count all train files with this DocumentName that are processed, and one with Process false, and Count all train files with this DocumentName that are not processed. [0] contains the group with false Processed, [1] has true Processed.

To make SubGroups the trainFileswithThisDocumentNames is scanned only once.

One final Select will make your query complete:

.Select(group => new DashboardCountDto
{
     DocumentName = group.DocumentName,
     UnProcessed = group.SubGroup[0].Count,
     Processed = group.SubGroup[1].Count,
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM