Serialize.Linq icon indicating copy to clipboard operation
Serialize.Linq copied to clipboard

Error converting type: Bug or implementation issue - please help

Open jacodv opened this issue 3 years ago • 3 comments

Describe the bug We have a generic report generator, it receives IQueryable<T> and OData query string. I need to change it to accept IQueryable<T> and Expression.

The report engine must execute var results = records.Provider.CreateQuery<T>(expression);

Below is a simple test

To Reproduce

  • Dotnet 6
[Test]
    public void CreateQuery_GivenExpression_ShouldGenerateReport()
    {
      // arrange
      Setup();
      var emptyList = new List<OutputChannelLog>().AsQueryable();
      var query = emptyList.Where(x => x.Channel == OutputChannelCodes.Email);
      var expression = query.Expression;
      var settings = new FactorySettings(){UseRelaxedTypeNames = true};
      var expressionSerializer = new ExpressionSerializer(new JsonSerializer(), settings);
      var expressionText = expressionSerializer.SerializeText(expression);

      Console.WriteLine(@$"Expression: {expression}");
      Console.WriteLine(@$"ExpressionText: {expressionText}");

      var user = Builder<User>.CreateNew().WithValidData().Build();

      var dbItems = Builder<OutputChannelLog>
        .CreateListOfSize(4)
        .TheFirst(2)
        .With(x => x.Channel = OutputChannelCodes.Sms)
        .TheNext(2)
        .With(x => x.Channel = OutputChannelCodes.Email)
        .Build();
      var dbQuery = dbItems.AsQueryable();


      // action
      var reportItems = dbQuery.Provider.CreateQuery<OutputChannelLog>(expressionSerializer.DeserializeText(expressionText));

      // assert
      reportItems.Count().Should().Be(2);
    }

Expected behavior Filter the records from 4 to 2

Screenshots image

jacodv avatar Oct 27 '22 09:10 jacodv

I have also tried a simple type with the DataContract attribute. But adding the [Datacontract] attribute to all our models are not an option if that was the requirement.

** Simple Type **

[DataContract]
  public class OutputChannelLogTest
  {
    public string CreatedBy { get; set; }
    public string Channel { get; set; }
  }

Updated Test

[Test]
    public void CreateQuery_GivenExpression_ShouldGenerateReport()
    {
      // arrange
      Setup();
      var emptyList = new List<OutputChannelLogTest>().AsQueryable();
      var query = emptyList.Where(x => x.Channel == "Email");
      var expression = query.Expression;
      var settings = new FactorySettings(){UseRelaxedTypeNames = true};
      var expressionSerializer = new ExpressionSerializer(new JsonSerializer(), settings);
      var expressionText = expressionSerializer.SerializeText(expression);

      Console.WriteLine(@$"Expression: {expression}");
      Console.WriteLine(@$"ExpressionText: {expressionText}");

      var dbItems = Builder<OutputChannelLogTest>
        .CreateListOfSize(4)
        .TheFirst(2)
        .With(x => x.Channel = "Sms")
        .TheNext(2)
        .With(x => x.Channel = "Email")
        .Build();
      var dbQuery = dbItems.AsQueryable();


      // action
      var reportItems = dbQuery.Provider.CreateQuery<OutputChannelLogTest>(
        expressionSerializer.DeserializeText(expressionText));

      // assert
      reportItems.Count().Should().Be(2);
    }

jacodv avatar Oct 27 '22 10:10 jacodv

Did you find a solution for this? I get this error when serializing an expression with an StringComparison enum in it.

Edit: I found the solution. There is an AddKnownType method in every serializer.

evaanp avatar Jun 12 '23 11:06 evaanp

I did not. I reverted to getting the actual query from the provider, in my case MongoDB. Then I recreate the IQueryable<T> from the actual query and work with the result.

Look at Remote.Linq. I came close to solving the problem with that package, but still not all the permutations.

jacodv avatar Jun 12 '23 11:06 jacodv