Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expressions on dynamic objects #136

Closed
NickDarvey opened this issue Jan 8, 2018 · 4 comments
Closed

Expressions on dynamic objects #136

NickDarvey opened this issue Jan 8, 2018 · 4 comments

Comments

@NickDarvey
Copy link
Contributor

Hi,

I'm wondering what the story is for System.Linq.Dynamic.Core and types that aren't known till runtime. Is this supported right now, and if it's not, will it be one day?

Right now, I have an IEnumerable<dynamic> I can that I'd like to query. Is there any way I can compose a query on top of that? Is there any other way you know of for handling this case?
(The collection contains ExpandoObjects from a JSON payload deserialized by Json.NET. I see you have a test for JObjects but we don't want to be bound to that type as we may have multiple serializers.)

There is a test in there for verifying a Select on a collection of dynamic objects, but it's disabled right now.

Repro

Run this test.

//[Fact]
public void ExpressionTests_Select_ExpandoObjects()
{
    //Arrange
    dynamic a = new ExpandoObject();
    a.Name = "a";
    a.BlogId = 100;
    dynamic b = new ExpandoObject();
    b.Name = "b";
    b.BlogId = 100;
    var list = new List<dynamic> { a, b };
    IQueryable qry = list.AsQueryable();

    var result = qry.Select("it").Select("BlogId");

    //Assert
    Assert.Equal(new[] { 100, 200 }, result.ToDynamicArray<int>());
}

Expected

Passes.

Actual

It's commented out. It fails when running it:

Message: System.Linq.Dynamic.Core.Exceptions.ParseException : No property or field 'BlogId' exists in type 'Object'

@StefH
Copy link
Collaborator

StefH commented Jan 8, 2018

Also related to #132

@StefH
Copy link
Collaborator

StefH commented Jan 8, 2018

A possible solution could be that a new class is defined in this library which keeps the information about the properties.
And the properties can be defined with the help from https://github.com/StefH/System.Linq.Dynamic.Core/blob/10fc9a2ec8677f638210804c0ca636de021e6c9a/src/System.Linq.Dynamic.Core/DynamicProperty.cs

So prototype code would be:

var property1 = new DynamicProperty("BlogId", typeof(int));
var property2 = new DynamicProperty("Name", typeof(string));
var a = new DynamicObject(property1, property2);
a.Name = "a";
a.BlogId = 100;

var list = new List<dynamic> { a, a };
IQueryable qry = list.AsQueryable();

var result = qry.Select("it").Select("BlogId"); // At this point the library should understand that the objects special.

// Maybe update the interface so that the type-information is also added?
// like:
var result = qry.Select(new [ property1, property2 ], "it").Select("BlogId");

@jogibear9988
Copy link
Contributor

@StefH
Copy link
Collaborator

StefH commented Sep 7, 2018

Hello @NickDarvey and @jogibear9988,

I've written some code which I use in WireMock.net which generated a select string based on a JObject. Code is here https://gist.github.com/StefH/27058744b2268fe8069c2b9641804214

And works like:

// Assign
var j = new JObject
{
    {"U", new JValue(new Uri("http://localhost:80/abc?a=5"))},
    {"N", new JValue((object) null)},
    {"G", new JValue(Guid.NewGuid())},
    {"Flt", new JValue(10.0f)},
    {"Dbl", new JValue(Math.PI)},
    {"Check", new JValue(true)},
    {"Items", new JArray(new[] {new JValue(4), new JValue(8)})},
    {
        "Child", new JObject
        {
            {"ChildId", new JValue(4)},
            {"ChildDateTime", new JValue(new DateTime(2018, 2, 17))},
            {"TS", new JValue(TimeSpan.FromMilliseconds(999))}
        }
    },
    {"Id", new JValue(9)},
    {"Name", new JValue("Test")}
};

// Act
string line = JsonUtils.GenerateDynamicLinqStatement(j);

// Assert
var queryable = new[] {j}.AsQueryable().Select(line);
bool result = queryable.Any("Id > 4");
Check.That(result).IsTrue();

Check.That(line).IsEqualTo("new (Uri(U) as U, null as N, Guid(G) as G, double(Flt) as Flt, double(Dbl) as Dbl, bool(Check) as Check, (new [] { int(Items[0]), int(Items[1])}) as Items, new (int(Child.ChildId) as ChildId, DateTime(Child.ChildDateTime) as ChildDateTime, TimeSpan(Child.TS) as TS) as Child, int(Id) as Id, string(Name) as Name)");

This could be a solution for your problem?
Closing this issue for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants