Search code examples
asp.netasp.net-mvcentity-frameworklinq-to-objects

LINQ dynamic property in select


// Hi everyone

i do this call in Action :

    [HttpGet]
    public virtual ActionResult JsonGetProvinces(int countryId)
    {
        //WebSiteContext WbContext = new WebSiteContext();
        //UnitOfWork UnitofWork = new UnitOfWork(WbContext);

        var provinces =
            (
                from province in unitofWork.ProvinceRepository.All
                where province.CountryId == countryId
                select new
                {
                    Id = province.Id,
                    Name = province.GetType().GetProperty("Name_" + CultureManager.GetCurrentCultureShortName()).GetValue(province)
                }
            ).ToList();

        return Json(provinces, JsonRequestBehavior.AllowGet);
    }

something is wrong with my query :

        var provinces =
            (
                from province in unitofWork.ProvinceRepository.All
                where province.CountryId == countryId
                select new
                {
                    Id = province.Id,
                    Name = province.GetType().GetProperty("Name_" + CultureManager.GetCurrentCultureShortName()).GetValue(province)
                }
            ).ToList();

Particulary, Name = province.GetType().GetProperty("Name_" + CultureManager.GetCurrentCultureShortName()).GetValue(province)

In BDD, there is Name_fr, Name_en columns and i'm trying to take one dynamically... Is it possible ?

Of course, i can take both and choose dynamically the column in View but i would to know how do...

Thank you for your help


Solution

  • EF can not translate function calls to SQL. Using expression trees can be comlicated see this question

    Here is a sample with expression trees. The GetQuery2 is the same as GetQuery but with expression tree and a propertyname parameter.

    public static IQueryable<Foo> GetQuery(BlogContext context)
    {
        var query = from x in context.BlogEntries
                    select new Foo
                    {
                        NameX = x.Name   
                    };
        return query;
    }
    
    
    public static IQueryable<Foo> GetQuery2(BlogContext context, string propertyName)
    {
    
        ConstructorInfo ci = typeof(Foo).GetConstructor(new Type[0]);
        MethodInfo miFooGetName = typeof(Foo).GetMethod("set_NameX");
        MethodInfo miBlogEntry = typeof(BlogEntry).GetMethod("get_" + propertyName);
    
        ParameterExpression param = Expression.Parameter(typeof(BlogEntry), "x");
    
        IQueryable<Foo> result = Queryable.Select<BlogEntry, Foo>(
                                    context.BlogEntries,
                                    Expression.Lambda<Func<BlogEntry, Foo>>(
                                        Expression.MemberInit(
                                            Expression.New(ci, new Expression[0]),
                                            new MemberBinding[]{
                                                Expression.Bind(miFooGetName, 
                                                                Expression.Property(param,
                                                                miBlogEntry))}
                                        ),
                                        param
                                    )
                                    );
        return result;
    }
    

    It is easier the fetch all all language strings and write an additional Property Name that does the magic.