-1

I'm trying to limit which fields are returned by an API based on a parameter called fields which I accept multiple strings doing this

private readonly string[] fields;

public string[] SelectiveSerializer(string fields)
{
    string[] _fields;
    var fieldColl = fields.Split(',');
    _fields = fieldColl
        .Select(f => f.ToLower().Trim())
        .ToArray();
    return _fields;

}

I want to be able to choose what I return based on whatever the user gives me in _fields. Normal way to do it:

 var linq = (from entity in db.users
             where entity.ID== id
              && entity.ON== false
             select( new {
             ID = entity.ID,
             FirstName = entity.FirstName,
             LastName =entity.LastName,
             FotherName = entity.FotherName
             }).ToList();

but here I have to specify the fields in Select (ID, FirstName ..etc), which I want it to be dynamic based on what fields[] has. Is there a way to do this?

sort of this (which is wrong):

var linq = (from entity in db.users
             where entity.ID== id
              && entity.ON== false
             select( new {
             foreach (string s in _fields)
             {
                    entity.s;
             }
             }).ToList();
0x2bad
  • 308
  • 2
  • 11

2 Answers2

0

Use a ternary expression for each assignment

var user = entityContext.Users.Where(u => u.ID == id)
    .Select(u => new {
        ID =  _fields.Contains['id'] ? u.ID : 0,
        FirstName = _fields.Contains['firstname'] ? u.FirstName : null,
        LastName = _fields.Contains['lastname'] ? u.LastName : null,
        otherName = _fields.Contains['othername'] ? u.otherName : null
    })
    .ToList();

I also would put the field names in a HashSet<string> for a better performance.

var _fields = new HashSet<string>(fields.Split(',').Select(f => f.ToLower().Trim()));

This solution keeps all the properties but sets the unwanted ones to null. If you want to dynamically add properties, see this other SO question: How to dynamically create a class in C#?. But note that this only useful in scenarios where objects of this type are processed dynamically as well.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • is't this going to return all fields but with null if not chosen? – 0x2bad Nov 28 '17 at 18:47
  • 1
    Yes. You cannot have a type with variable fileds unless using some heavy reflection stuff. Even if it is an anonymous type. See SO question [How to dynamically create a class in C#?](https://stackoverflow.com/q/3862226/880990). – Olivier Jacot-Descombes Nov 28 '17 at 18:51
0

I was finally able to do this with minimal work. assuming the filter is a string list. string array.

so to avoid reflection and all that jazz, I iterate over each record and see if the variable is in the filter list, then create a dic entry with (var,val) assuming that no duplicate var in the same record, which can be catch if you want but I don't have this issue. Then at the end add that dic to a list. the method accept anonymous type list and a filter list.

public static List<Dictionary<string, object>> filteredList(IEnumerable source, string[] filter)
    {
        var filteredList = new List<Dictionary<string, object>>();
        foreach (var single in source)
        {
            var type = single.GetType();
            var props = type.GetProperties();
            var singleRecord = new Dictionary<string, object>();
            foreach (var v in props)
            {
                if (filter.Contains(v.Name))
                {
                    var tempValue = type.GetProperty(v.Name).GetValue(single, null);
                    singleRecord.Add(v.Name, tempValue);
                }

            }
            filteredList.Add(singleRecord);
        }
        return filteredList;
    }
0x2bad
  • 308
  • 2
  • 11