Linq-запрос с агрегатами - PullRequest
2 голосов
/ 25 февраля 2009

Я хочу написать элегантный запрос linq для обработки следующей объектной модели SAMPLE:

    class Category
    {
        public string Name { get; set; }        
        public IList<Product> Products { get; set;}        
    }

    class Product
    {
        public string Title { get; set; }
        public IList<Photo> Photos { get; set; }
    }

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

Я создал следующий запрос для получения идентификатора фотографии:

    var query = from category in Factory.GetCategories()
                where category.Name == "Cameras"
                select (from product in category.Products
                        where product.Title == "Sony"
                        select (from photo in product.Photos
                                select photo.Id)
                               );

    var v = query.ToList();

На данный момент запрос не отображается правильно, я должен добавить FirstOrDefault () к каждому из Sub Selects!

var query = from category in Factory.GetCategories()
                where category.Name == "Cameras"
                select (from product in category.Products
                        where product.Title == "Sony"
                        select (from photo in product.Photos
                                select photo.Id).FirstOrDefault()
                               ).FirstOrDefault();

var v = query.ToList();

Есть ли лучший способ сделать это? Игнорирование того факта, что мы не имеем дело с базой данных и PK / FK, не в игре.

Я действительно хочу избежать написания большого цикла for, когда я могу сделать то же самое в запросе linq:

foreach (var category in Factory.GetCategories())
            {
                if (category.Name == "Camera")
                {
                    foreach (var product in category.Products)
                    {
                        if (product.Title == "Sony")
                        {
                            foreach (var photo in product.Photos)
                            {
                                //get data
                                int id = photo.Id;
                            }
                        }
                    }
                }                
            }

Фактическая реализация является более сложной, чем эта простая объектная модель. Я хочу получить основную идею из этого простого примера, чтобы применить ее к своей реальной объектной модели.

Ура!

Ответы [ 4 ]

5 голосов
/ 25 февраля 2009

Вы просто хотите, чтобы сплющенные идентификаторы?

        var query = from category in Factory.GetCategories()
                    where category.Name == "Cameras"
                    from product in category.Products
                    where product.Title == "Sony"
                    from photo in product.Photos
                    select photo.Id;
2 голосов
/ 25 февраля 2009

Ну, да - вы должны добавить FirstOrDefault, потому что нет такой вещи, как «фотография» ID. На каждой камере может быть много фотографий - что вы хотите?

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

var query = from category in Factory.GetCategories()
            where category.Name == "Cameras"
            from product in category.Products
            where product.Title == "Sony"
            select product.Photos.Select(photo => photo.Id)
                                 .FirstOrDefault();

Обратите внимание, что это вернет 0 для продукта без фотографий. Это то, что вы хотите?

Если вы будете более ясны в своих требованиях, мы будем лучше подготовлены, чтобы помочь вам.

РЕДАКТИРОВАТЬ: если вам нужен только самый первый идентификатор любой камеры Sony, используйте:

var query = from category in Factory.GetCategories()
            where category.Name == "Cameras"
            from product in category.Products
            where product.Title == "Sony"
            from photo in product.Photos
            select photo.Id;
var firstId = query.FirstOrDefault();
1 голос
/ 25 февраля 2009

Тот же ответ, что и у всех, но с вызовами методов расширения вместо понимания запросов. SelectMany позволяет вам "распаковать" дочернюю коллекцию и продолжить запросы на этом уровне.

var query = Factory.GetCategories()
  .Where(category => category.Name == "Cameras")
  .SelectMany(category => category.Products)
  .Where(product => product.Title == "Sony")
  .SelectMany(product => product.Photos)
  .Select(photo => photo.Id);
0 голосов
/ 25 февраля 2009
        var ids = from category in Factory.Categories
                  where category.Name == "Cameras"
                  from product in category.Products
                  where product.Title == "Sony"
                  from photo in product.Photos
                  select photo.Id;

Возвращает все идентификаторы фотографий, перечислимое пусто, когда нет фотографий. Если вы хотите первый, или по умолчанию 0:

var result = ids.FirstOrDefault();
...