2016-10-17 2 views
0

Ok, я написал ниже LINQ to Entities запроса (достаточно близко к моему C# запрос с указанием ниже)Linq для фильтрации вложенного списка

var itemss = filteredstudents 
.Where(x => x.SubjectTypes.Any(y => y.SubjectItem.Any(z => z.Name == value1))).ToList(); 

еще немного проблема, потому что, когда тип SubjectItem имеет два элемента и один из них совпадают с value1. он все равно возвращает оба. Он должен возвращать только соответствующую запись. Я знаю, проблема в том, что с Any, но не уверен Any заменить на что?

foreach (StudentDTO student in filteredstudents) 
{ 
    bool valid = true; 
    foreach (SubjectTypes subjectType in student.SubjectTypes) 
    { 
     string value1 = subjectType.SubjectItem.Select(x => x.value1).First(); 
     Guid StId = _context.Items.Where(x => x.Name == value1).FirstOrDefault(); 

     if (StId != null) 
      valid = true; 
     else 
     { 
      valid = false; 
      _log("create log"); 
     } 
    } 
    if (valid) 
     filteredstudentsWithUnits.Add(student); 
} 

Пример ввода

{"Name":"ABC", 
"Age":12, 
,"SubjectTypes": 
[ 
{"Id":"1","Description":""Description","SubjectItem":[{"Id":"1","Marks":12,"Name":"aaa"}]}, 
{"Id":"1","Description":""Description","SubjectItem":[{"Id":"1","Marks":12,"Name":"aaa"}]}, 
{"Id":"1","Description":""Description","SubjectItem":[{"Id":"1","Marks":12,"Name":"bbb"}]} 
] 
} 

Ожидаемый результат

{"Name":"ABC", 
"Age":12, 
,"SubjectTypes": 
[ 
{"Id":"1","Description":""Description","SubjectItem":[{"Id":"1","Marks":12,"Name":"aaa"}]}, 
{"Id":"1","Description":""Description","SubjectItem":[{"Id":"1","Marks":12,"Name":"aaa"}]}, 

] 
} 
+0

пожалуйста, поделитесь отношения между '' SubjectTypes' и SubjectItem' – Jacky

+0

Также будет полезно, если вы размещаете данные примера и ожидаемые результаты –

+0

Можете ли вы объяснить, что должно произойти в случае нескольких элементов? Если он возвращается только в том случае, если есть один элемент, и он соответствует, и если да, то в чем проблема, с которой вы сталкиваетесь (это не сложнее, чем другие вещи, которые вы здесь делаете) – Chris

ответ

0

Заканчивать следующий код с тестовых данных это фильтровать коллекцию вложенного списка , Существует два решения: первое простое применение запроса Linq, другое - сглаживание и повторная группировка, которые могут использоваться для относительно сложных сценариев, которые требуют большего контроля над данными.

данных испытаний:

Создано StudentDTO со списком в качестве вложенной коллекции, которая должна быть отфильтрована

public class StudentDTO 
{ 
    public string SName { get; set; } 

    public int Age { get; set; } 

    public List<Subject> Subjects { get; set; } 

    public static IEnumerable<StudentDTO> FetchList() 
    { 
     List<StudentDTO> testList = new List<StudentDTO>(); 

     testList.Add(new StudentDTO { SName = "M", Age = 12, Subjects = new List<Subject>() { new Subject {Id = 1, Marks = 100, Name = "AAA"} , 
                          new Subject {Id = 1, Marks = 98, Name = "AAA"}, 
                          new Subject {Id = 1, Marks = 100, Name = "BBB"}     
                          }}); 

     return testList; 
    } 
} 

public class Subject 
{ 
    public int Id{ get; set; } 

    public int Marks{ get; set; } 

    public string Name { get; set; } 

} 

Решение: 1 (Простое приложение Linq запросов)

var studentListFiltered = 
studentList.Select(x => 
        new StudentDTO { 
            SName = x.SName, 
            Age = x.Age, 
            Subjects = x.Subjects 
               .Where(n => n.Name == "AAA").ToList() 
            }); 

Решение: 2 (Сведение и перегруппировка)

- Создать StudentDTO список, содержащие данные испытуемые

var studentList = StudentDTO.FetchList(); 

- Свести список, чтобы легко фильтровать данные

var studentListFlattened = 
    studentList.SelectMany(x => x.Subjects.Select(y => new {x.SName,x.Age,y.Id,y.Marks,y.Name})); 

- Фильтровать данные, группировать их с помощью столбцов родительских объектов и создавать исходную вложенную структуру

var studentListFiltered = 
    studentListFlattened.Where(x => x.Name == "AAA") 
         .GroupBy(x => new { SName = x.SName, Age = x.Age }) 
         .ToDictionary(x => x.Key, x => x.Select(n => new Subject {Id = n.Id,Marks = n.Marks,Name = n.Name}).ToList()) 
         .Select(x => new StudentDTO{ SName = x.Key.SName, Age = x.Key.Age, Subjects = x.Value}); 

studentListFiltered содержит окончательный результат с фильтрованным вложенным списком. Аналогичную стратегию/код можно использовать для фильтрации любого уровня вложенного списка по используемому случаю

0

Вы можете сначала отфильтровать список, используя .Where, а затем использовать .Select для создания новой коллекции, содержащей только те данные, которые вы хотите. Что-то вроде следующего может работать:

var itemss = filteredstudents 
    .Where(s => s.SubjectTypes.Any(st => st.SubjectItem.Any(si => si.Name == value1))) 
    .Select(s => new StudentDTO 
    { 
     Name = s.Name, 
     Age = s.Age, 
     SubjectTypes = s.SubjectTypes.Where(st => st.SubjectItem.Any(si => si.Name == value1)) 
      .Select(st => new SubjectType 
      { 
       Id = st.Id, 
       Description = st.Description, 
       SubjectItem = st.SubjectItem.Where(si => si.Name == value1).ToList() 
      }).ToList() 
    }) 
    .ToList(); 
0

Это позволит решить проблему, но может быть и лучшими способами сделать это, и я опустил некоторые свойства, такие как идентификаторы и отмечает, что вам нужно добавить.

var items = filteredstudents.Select(s => new StudentDTO 
{ 
    Name = s.Name, 
    SubjectTypes = s.SubjectTypes.Select(st => new SubjectType 
    { 
     Description = st.Description, 
     SubjectItems = st.SubjectItems.Where(si => si.Name == "AAA").ToList() 
    }).Where(x => x.SubjectItems.Count > 0).ToList() 
}); 
Смежные вопросы