MoonKnight
MoonKnight

Reputation: 23831

LINQ Deffered Execution Subtlety

All, I have recently localised the entire aplication and I am faced with the following problem;I have the following LINQ query in my application

var ccsum = from a in dtSumGL2.AsEnumerable()
    group Math.Abs(a.Field<double>(strpcPSPassBegCost)) by new 
    {
       BaseCC = a.Field<string>(strpcBaseCC)
    }
       into g
       select new
       {
          g.Key.BaseCC,
          PSPassBegCost = g.Sum()
       };

This is creating a new object ccsum which we use to create a DataTable and subsequently populate an SQL Server database.

The problem is that each of the new items being created in the DataTable with column names BaseCC and PSPassBegCost, but these names do not matched the German version of these names. Now for my question: is there a way to do something like:

var ccsum = from a in dtSumGL2.AsEnumerable()
    group Math.Abs(a.Field<double>(strpcPSPassBegCost)) by new 
    {
       BaseCC = a.Field<string>(strpcBaseCC)
    }
       into g
       select new
       {
          g.Key.BaseCC as Resources.BaseCC,
          PSPassBegCost = g.Sum() as Resources.PSPassBegCost 
       };

so that I can name the tables according to their localised names?


Edit. The code that retrieve a DataTable from ccsum is

fooDt = Utils.LINQToDataTable(ccsum);

and

public static DataTable LINQToDataTable<T>(IEnumerable<T> varlist)
{

    DataTable dtReturn = new DataTable();
    PropertyInfo[] oProps = null;
    if (varlist == null) 
    return dtReturn;

    foreach (T rec in varlist)
    {
        // Use reflection to get property names, to create 
        // table, Only first time, others will follow.
        if (oProps == null)
        {
            oProps = ((Type)rec.GetType()).GetProperties();
            foreach (PropertyInfo pi in oProps)
            {
                Type colType = pi.PropertyType;
                if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                {
                    colType = colType.GetGenericArguments()[0];
                }
                dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
            }
        }

        DataRow dr = dtReturn.NewRow();
        foreach (PropertyInfo pi in oProps)
        {
            pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue(rec, null);
        }
        dtReturn.Rows.Add(dr);
    }
    return dtReturn;
}

Thanks for your time.

Another approach might be to rename the 'columns' in the ccsum object as a post-processing step although the values of sumcc are not populated until they are requested at run-time - any other ideas?

Upvotes: 1

Views: 154

Answers (3)

Paul Turner
Paul Turner

Reputation: 39685

Attempting to localize components of your system for greater human comprehension is a laudable goal, but it will give you challenges in using the the vast majority of tools and libraries: generally database tooling expects these things to be constant and ignorant of localization.

If you wish your database tables to be easier to understand, perhaps a more practical solution would be to produce localized views instead? The views could live in a de schema and be one-to-one translations of your tables. This would allow you to leverage a lot of the standard tooling, keeping your system in a consistent "neutral" culture internally (whatever your development culture is) and providing translations over the top of these wherever required.

I think trying to embed this kind of localization into the heart of your system is likely to not be worth the cost of working around the expectations of most developers and toolsets and you're better providing a façade.

Upvotes: 2

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236328

Create class or enum which will map column indexes to some readable names:

public static class SumGLColumn
{
    public const int BaseCC = 0;
    public const int PSPassBegCost = 1;
}

And use column indexes instead of column names to query your datatable:

var ccsum = from a in dtSumGL2.AsEnumerable()
            group Math.Abs(a.Field<double>(SumGLColumn.PSPassBegCost)) 
                  by a.Field<string>(SumGLColumn.BaseCC) into g
            select new {
               BaseCCg = g.Key,
               PSPassBegCost = g.Sum()
            };

Upvotes: 2

SebastianStehle
SebastianStehle

Reputation: 2457

This is not possible. In the select statement you define an anonymous type. This is not a language feature, but a compiler-feature, which means that the compiler creates a class for this type with the properties you define.

This means that the compiler must know the names at compile time. If you want something more dynamic, I recommend you to use a dictionary:

select new Dictionary<string, object> 
{ 
    { Resources.BaseCC, g.Key.BaseCC },
    { Resources.PSPassBegCost , g.Sum() }
};

Upvotes: 1

Related Questions