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

"Target object is not an ExpandoObject" exception being thrown when using GroupBy #416

Closed
FernandoGPinto opened this issue Aug 25, 2020 · 6 comments
Assignees

Comments

@FernandoGPinto
Copy link

FernandoGPinto commented Aug 25, 2020

Hi

I am using dynamic GroupBy on a union of records and getting a Target object is not an ExpandoObject exception thrown by DynamicIndex when trying to run the query and obtain a list of records using the following code:

var fireExits = _context.View_SupplyChainSurveyResults.Select("new ( FireExits As FireAndEmergency )").AsEnumerable();

var fireExtinguishers = _context.View_SupplyChainSurveyResults.Select("new ( FireExtinguishersWorkArea As FireAndEmergency )").AsEnumerable();

var unionAll = fireExits.Concat(fireExtinguishers).AsQueryable();

var recordList = unionAll.GroupBy("FireAndEmergency").Select("new (Key as Label, Count() as Count)").ToDynamicList();

DynamicIndex only seems to be called by the GroupBy operator. Is there a limitation to this operator that I am anware of or am I missing a conversion?

Exception:

Exception thrown: 'System.InvalidOperationException' in System.Linq.Dynamic.Core.dll
An exception of type 'System.InvalidOperationException' occurred in System.Linq.Dynamic.Core.dll but was not handled in user code
Target object is not an ExpandoObject
  at System.Linq.Dynamic.Core.Dynamic.DynamicIndex(Object obj, String name)   
  at System.Linq.Lookup`2.Create[TSource](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
  at System.Linq.GroupedEnumerable`3.GetEnumerator()
  at System.Linq.EnumerableQuery`1.GetEnumerator()
  at System.Linq.EnumerableQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
  at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
  at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
  at SupplyChainWebApp.Data.SurveyDataAccessLayer.GetResponseAnalysisGroupedChartsData[T](Int32 month, String contract, String chartType)
@JonathanMagnan JonathanMagnan self-assigned this Aug 26, 2020
@JonathanMagnan
Copy link
Member

Hello @FernandoGPinto ,

Do you think you could provide a runnable project sample for this issue? It will help my developer to get started to investigate it faster and make sure nothing is missing.

Providing a project sample is now REQUIRED. It happened too many times that something was missing to investigate and/or answer an issue.

Try to create a new project with only the minimal code (having too many non-related codes doesn’t help either).

You can send it to [email protected] if you need to keep the source private

Best Regards,

Jon


Performance Libraries
context.BulkInsert(list, options => options.BatchSize = 1000);
Entity Framework ExtensionsEntity Framework ClassicBulk OperationsDapper Plus

Runtime Evaluation
Eval.Execute("x + y", new {x = 1, y = 2}); // return 3
C# Eval FunctionSQL Eval Function

@FernandoGPinto
Copy link
Author

FernandoGPinto commented Aug 26, 2020

Hi @JonathanMagnan,

Thanks for reponding so quickly. Below you can find a simplified runnable version of my code. The exception thrown is the same.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
					
public class Program
{		
	public static void Main()
	{
		var list = GenerateDummyData();

		var fireExits = list.Select("new ( FireExits As FireAndEmergency )").AsEnumerable();

		var fireExtinguishers = list.Select("new ( FireExtinguishersWorkArea As FireAndEmergency )").AsEnumerable();

		var unionAll = fireExits.Concat(fireExtinguishers).AsQueryable();

		var recordList = unionAll.GroupBy("FireAndEmergency").Select("new (Key, Count() as Count)");

		foreach (var record in recordList)
		{
			string str = record.ToString();
			Console.WriteLine(str);
		}
	}
	
	public static IQueryable<View_SupplyChainSurveyResults> GenerateDummyData()
	{
		var list = new List<View_SupplyChainSurveyResults>();

		var ex1 = new View_SupplyChainSurveyResults();
		ex1.FireExits = false;
		ex1.FireExtinguishersWorkArea = true;

		var ex2 = new View_SupplyChainSurveyResults();
		ex2.FireExits = true;
		ex2.FireExtinguishersWorkArea = false;

		var ex3 = new View_SupplyChainSurveyResults();
		ex3.FireExits = true;
		ex3.FireExtinguishersWorkArea = false;

		list.Add(ex1);
		list.Add(ex2);
		list.Add(ex3);

		return list.AsQueryable();
	}
	
	public class View_SupplyChainSurveyResults
    {
        public bool FireExits { get; set; }
        public bool FireExtinguishersWorkArea { get; set; }
    }
}

@JonathanMagnan
Copy link
Member

Thank you :) My developer will look at it

@JonathanMagnan
Copy link
Member

Hello @FernandoGPinto ,

Unfortunately, I don't think it will be possible to support your case, I believe you reached the limitation of the library.

Anonymous type is created on the fly, even if they have similar different, they are different type so trying to make a union on both lists make it currently impossible to do such request.

I don't think anything will be done here due to the amount of time required to make it works.

@StefH
Copy link
Collaborator

StefH commented Sep 8, 2020

Actually, the union/concat (var unionAll = fireExits.Concat(fireExtinguishers).AsQueryable();) does work, because there is a check in the code to reuse a dynamic generated type.
(https://github.com/zzzprojects/System.Linq.Dynamic.Core/blob/master/src/System.Linq.Dynamic.Core/DynamicClassFactory.cs#L117)

So because both anonymous classes have a property FireAndEmergency which is a bool, they are the same. So they can be used in the Union call.

(possible) solution

Hello @FernandoGPinto, a possible solution is to introduce a real class to capture the data.

See example c# code below:

class Program
{
    public static void Main()
    {
        var list = GenerateDummyData();

        var fireExits = list.Select<X>("new ( FireExits As FireAndEmergency )"); // Cast to X

        var fireExtinguishers = list.Select<X>("new ( FireExtinguishersWorkArea As FireAndEmergency )"); // Cast to X

        var unionAll = fireExits.Union(fireExtinguishers).AsQueryable();

        var recordList = unionAll.GroupBy("FireAndEmergency").Select("new (Key, Count() as Count)");

        foreach (var record in recordList)
        {
            string str = record.ToString();
            Console.WriteLine(str);
        }
    }

    public static IQueryable<View_SupplyChainSurveyResults> GenerateDummyData()
    {
        var list = new List<View_SupplyChainSurveyResults>();

        var ex1 = new View_SupplyChainSurveyResults();
        ex1.FireExits = false;
        ex1.FireExtinguishersWorkArea = true;

        var ex2 = new View_SupplyChainSurveyResults();
        ex2.FireExits = true;
        ex2.FireExtinguishersWorkArea = false;

        var ex3 = new View_SupplyChainSurveyResults();
        ex3.FireExits = true;
        ex3.FireExtinguishersWorkArea = false;

        list.Add(ex1);
        list.Add(ex2);
        list.Add(ex3);

        return list.AsQueryable();
    }

    public class X
    {
        public bool FireAndEmergency { get; set; }
    }

    public class View_SupplyChainSurveyResults
    {
        public bool FireExits { get; set; }
        public bool FireExtinguishersWorkArea { get; set; }
    }
}

image

@FernandoGPinto
Copy link
Author

Hi @StefH @JonathanMagnan

Thank you for taking time to look into this and for proposing a solution. It works great and has solved the issue I was grappling with 👍

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