System.Linq.Dynamic.Core : How do I make a select many correctly?

.net c# dynamic-linq linq

Question

I am new to the System.Linq.Dynamic.Core. I have this:

Let's say we have:

Packs = new List<Pack>
{
    new Pack()
    {
        IdAtSource="Pack1",
        Equipments= new List<Equipment>()
        {
            new Equipment
            {
                Id=1,
                GenericEquipment = new GenericEquipment()
                {
                    Id=7
                }
            }
        }
    },
    new Pack()
    {
        IdAtSource="Pack2",
        Equipments= new List<Equipment>()
        {
            new Equipment
            {
                Id=2,
                GenericEquipment = new GenericEquipment()
                {
                    Id=1
                }
            },
            new Equipment
            {
                Id=2,
                GenericEquipment = new GenericEquipment()
                {
                    Id=2
                }
            }
        }
    }
}

I would like to select the Packs with Equipments, but in the selected Equipments I need to have only the one with Id=2 for Generic Equipment.(the result should contain a list of packs with list of equipments).

I've tried this:

querable.Where("Packs.Equipments.Select((GenericEquipment.Id)=1)");

but I feel I am waaay of target here. Also is there any documentation page on how to use this library?

Thanks a lot

1
2
11/13/2016 5:54:45 AM

Accepted Answer

The most recent version of Dynamic LINQ appears to be the project here, with the documentation here.


Generally, the only reason why you should require Dynamic LINQ over standard LINQ is when the types are not known at compile time.

If you know at compile time that the query will be against a List<Pack>, you can use stanadard LINQ, as in the following code (note that this modifies the original instances of Pack):

var usefulPacks = Packs.Select(pack => {
    pack.Equipments = pack.Equipments.Where(equipment => 
        equipment.GenericEquipment.Id == 1
    ).ToList(); 
}).Where(pack => pack.Equipments.Any()).ToList();

If you need code that doesn't modify the original instances, this code creates copies of the original instances:

var usefulPacks = Packs.Select(pack => {
    return new Pack() {
        IDAtSource = pack.IDAtSource,
        Equipments = pack.Equipments.Where(equipment => 
            equipment.GenericEquipment.Id == 1
        ).ToList(); 
    };
}).Where(pack => pack.Equipments.Any()).ToList();

Note that this isn't using .SelectMany.SelectMany is used to create a single enumerable from nested enumerables; here each Pack in the final list corresponds to a Pack in the original list.


Dynamic LINQ doesn't support modifying or initializing properties as part of the expression:

The expression language permits getting (but not setting) the value of any reachable public field, property, or indexer.

so the Equipments property cannot be changed / initialized to include only instances of Equipment that match the criteria.

In order to set the Equipments, you have two choices:

  1. Add a constructor to Pack which takes the appropriate arguments
  2. Write a static method on any class which takes the appropriate arguments

Add a constructor to Pack

You can add a constructor to Pack with the appropriate arguments, that sets Equipments:

Pack(int IDAtSource, IEnumerable<Equipment> equipments) {
    this.IDAtSource = IDAtSource;
    this.Equipments = equipments.ToList();
}

Then you could use the following:

IQueryable qry = Packs.AsQueryable();
qry = qry
    .Select("Pack(IDAtSource, Equipments.Where(GenericEquipment.ID=1))")
    .Where("Equipments.Any");

Define a static method

public static class MyPackMethods {
    public static Pack Create(int IDAtSource, IEnumerable<Equipment> equipments) {
        return new Pack() {
            IDAtSource = IDAtSource,
            Equipments = equipments.ToList()
        };
    }
}

and call:

IQueryable qry = Packs.AsQueryable();
qry = qry
    .Select("MyPackMethods.Create(IDAtSource, Equipments.Where(GenericEquipment.ID=1))")
    .Where("Equipments.Any");
0
12/3/2017 2:17:09 AM

Popular Answer

These should work:

var equipments= from pack in Packs where pack.Equipments.Any() select pack.Equipments;

var secondEquipments = from pac in equipments where       
pac.GenericEquipment.Id == 2 select pac;
//I could use one variable instead of 2 but that would look a little bit complex

Msdn Link(Sorry I'm at mobile so I can't rename it): https://msdn.microsoft.com/en-us/library/bb397927.aspx



Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow