LINQ to CSLA bug..??

LINQ to CSLA bug..??

Old forum URL: forums.lhotka.net/forums/t/6988.aspx


chachek posted on Friday, May 22, 2009

In CSLA 3.6.3, when trying to execute:

DateTime? maxLastUpdated = myBusinessList.Max(x => x.LastUpdated);

I get the following ArgumentException:

Object of type 'System.Func`2[My.Entities.BusinessEntity,System.Nullable`1[System.DateTime]]' cannot be converted to type 'System.Func`2[My.Entities.BusinessEntity,System.Nullable`1[System.Int32]]'.

It seems that the CslaQueryProvider is trying to use a different overload of the Max method.

It works when I cast myBusinessList to IEnumerable<BusinessEntity>

AaronErickson replied on Friday, May 22, 2009

Can you provide your implementation of myBusinessList? I just built a test that exercises Max with a similar lambda and was not able to repro this. I used a datetime for my prop, casted it to a DateTime?, and it worked. Here is my code:

CollectionExtendingIQueryable random = new CollectionExtendingIQueryable();

random.Add(new RandomThing(1));
random.Add(new RandomThing(2));
random.Add(new RandomThing(3));
random.Add(new RandomThing(4));
random.Add(new RandomThing(5));

var a = from r in random where r.SomeVal >= 0 select r;
Assert.IsTrue(a.Max(r => r.SomeDateTime) == new DateTime(5));
//did this last one to make sure the nullable isnt causing this issue
DateTime? maxDateTime = random.Max(r => r.SomeDateTime);

RockfordLhotka replied on Friday, May 22, 2009

This fails Aaron - though if you change the property type to DateTime instead of DateTime? it works, so it must have to do with Nullable<T>:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Csla;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      var list = new MyList();
      list.Add(new MyChild { Id = 5, ADate = DateTime.Parse("3/1/02") });
      list.Add(new MyChild { Id = 15, ADate = DateTime.Parse("4/1/01") });
      list.Add(new MyChild { Id = 2, ADate = DateTime.Parse("5/1/02") });
      list.Add(new MyChild { Id = 25, ADate = DateTime.Parse("3/1/03") });
      list.Add(new MyChild { Id = 1, ADate = DateTime.Parse("8/1/02") });

      var max = list.Max(c => c.Id);
      Console.WriteLine(max);
      DateTime? maxDate = list.Max(c => c.ADate);
      Console.WriteLine(maxDate);
      Console.ReadLine();
    }
  }

  [Serializable]
  public class MyList : Csla.BusinessListBase<MyList, MyChild>
  {
  }

  [Serializable]
  public class MyChild : Csla.BusinessBase<MyChild>
  {
    private static PropertyInfo<int> IdProperty = RegisterProperty<int>(c => c.Id);
    public int Id
    {
      get { return GetProperty(IdProperty); }
      set { SetProperty(IdProperty, value); }
    }

    private static PropertyInfo<DateTime?> ADateProperty = RegisterProperty<DateTime?>(c => c.ADate);
    public DateTime? ADate
    {
      get { return GetProperty(ADateProperty); }
      set { SetProperty(ADateProperty, value); }
    }
  }
}

AaronErickson replied on Friday, May 22, 2009

Excellent... working on fix...

AaronErickson replied on Friday, May 22, 2009

Just submitted a fix that should solve this issue. The method comparison routine that finds the correct Queryable to call when we dont do special handling was not handling certain classes of generic types. Issue should now be resolved.

A unit test has also been added to the test suite to exercise this issue.

Copyright (c) Marimer LLC