0

Im trying to implement a dynamic dto. First there will be a information manager where you can select the fields you want to return by the WebApi.

Later in the api you send a request to an endpoint with the DTO's Id you want. This method will recive the info, query it in the db and obtain the fields that integrate the DTO(dynamic number of fields):

   [Route("api/workers")]
    public IEnumerable<object> GetWorkers([FromRoute] string idEnterprise,int idDTO)
    {
        //lstDummyFields = _context.Dtos.Include("DtoFields").
           //Where(n=>n.idDto==idDTO).select(n=>n.DtoFields.name).ToList();

        //The property will look like this, the selected dto could have different properties(dynamic) but always call the same as the entity name fields
        List<string> lstDummyFields = new List<string>
        {
            "idWorker",
            "first_name",
            "last_name",
            "birthday",
            "adress"
        };

        dynamic dto = new ExpandoObject() as IDictionary<string,object>;
        foreach (var p in lstDummyProperty)
        {
            dto.Add(p, null);
        }


        return _context.workers.Where(n=>n.IdEnterprise==idEnterprise).select.(new { ???? }) .ToList();
    }

I dont know how to implement the select clause.Could be related to this post but its sligtly different.

https://stackoverflow.com/a/34726946/2642777

I'm close to the answer or im going the wrong way? Could throw some help to solve this please.

Tseng
  • 61,549
  • 15
  • 193
  • 205
Robert K
  • 130
  • 3
  • 16
  • Sort of like how OData works? – Neil Aug 22 '18 at 16:49
  • Why not fetch the data first, and then filter out the properties you don't want on the expando object? – Tseng Aug 22 '18 at 16:51
  • Otherwise you will have to choose the hard, non-trivial way to implement it: Building of dynamic Expression Trees (the way LINQ works and gets translated into by the compiler) using reflection and the Expression classes. See [Expression Trees](https://learn.microsoft.com/en-us/dotnet/csharp/expression-trees) – Tseng Aug 22 '18 at 16:52
  • @Tseng Cause you could have a very large set of information. Maybe not in the workers example but in another scenario. – Robert K Aug 22 '18 at 16:58
  • Why not just write a SQL query and load the results into a DataTable, instead of a LINQ expression returning a type? ADO.NET supports this scenario pretty well, and nothing at the EF level really does. – David Browne - Microsoft Aug 22 '18 at 17:00
  • Well, then you are out of luck. Consider using raw queries (still use prepared statements/sql injection save code) and bind to and dto or use a micro orm such as dapper for that task. Or even plain old ADO.NET. As you can [see here](https://learn.microsoft.com/en-us/dotnet/csharp/expression-trees-building#creating-nodes), expression trees are rather expressive (no pun intended). For a very simple lambda you 4 expressions and you need to build them in reverse (starting with the leaves and building up to the root) if you would want to get that working with ef core/linq – Tseng Aug 22 '18 at 17:11
  • Or... mhh you could try to use the [shadow properties](https://learn.microsoft.com/en-us/ef/core/modeling/shadow-properties) of EF Core, but that's not really clean neither, i.e. using `b => EF.Property(b, "LastUpdated")`, not sure that works with anonymous classes though – Tseng Aug 22 '18 at 17:14
  • Also some GIST example I just found on how to build an anonymous class with expression trees. https://gist.github.com/dcastro/9093000 But like I said, non-trivial code to get right and it gets quite complex for simple expressions with a few instructions – Tseng Aug 22 '18 at 17:21

2 Answers2

0

We don't know your case, maybe use Directory is better? But you can use this code:

        List<string> lstDummyFields = new List<string>
        {
            "idWorker",
            "first_name",
            "last_name",
            "birthday",
            "adress"
        };

        dynamic dto = new ExpandoObject();
        foreach (var p in lstDummyFields)
        {
            ((IDictionary<String, Object>)dto).Add(new KeyValuePair<string, object>( p, null));
        }
PWND
  • 409
  • 3
  • 11
0

Use Restier. It's a wrapper around OData (in 2 lines of code !) that means you can call the API with things like:

http://services.odata.org/v4/TripPinServiceRW/People?$top=2&$select=FirstName,LastName&$filter=Trips/any(d:d/Budget gt 3000)

Which is a dynamic query, filter, and field selection.

Neil
  • 11,059
  • 3
  • 31
  • 56