You don't tell LINQ to use the invariant culture. LINQ is only a collection of extension functions of the IEnumerable<T>
and IQueryable<T>
interfaces.
You are using a DbContext
. It seems this is an Entity Framework DbContext
, but even it is not, your DbContext
is supposed to hide from you in what format numbers are stored in the storage (which is usually a SQL database, but doesn't have to be, it can be a CSV-file, EXCEL, JSon, whatever).
If you look closely to your object DbContext.Model
, you'll see that the class of this object implements IQueryable<Model>
.
This means, that this object can hold two things: an Expression
and a 'Provider'. (ok, also an elementType, in your example this will be Model
, not meaningful in this discussion)
When you use DbContext.Model
as the starting point of your query, you are in fact changing the Expression
inside the IQueryable<Model>
. As long as you are not asking for the first element in of your sequence of models the Provider
is not used.
The Provider
hides from you how your sequence of Models is stored. The Provider
knows whether it is a relational database, or a CSV-file, or whatever. It is the task of the Provider
to translate the Expression
into a format that the storage understands and fetch the data from the storage.
For Entity Framework DbContexts, this usually means that the storage is a SQL(-like) database. The Provider
knows the database model and it knows how to translate your Expression
into SQL and how to communicate with your database.
After reading this, you should understand, that the user of you DbContext.Model object should not be aware in what format the storage saves decimals. It is the task of the Provider
to translate decimals into storage format. And if this storage format stores decimals as Spanish strings, then the Provider
should translate decimals into Spanish strings.
Now back to your question, because this knowledge does not solve your problem.
You should investigate why the Spanish notation seeps through to your DbContext.Models
It seems that the storage of your database was told to store Length as a string instead of a decimal.
If your database would be SQL, then a decimal would not have been saved as a string, but as a value with a certain precision.
If the database saves your Length as a string, then the designer of your database told entity framework that Model.Length
is a string, not a decimal. In that case, the definition of your Model
class does not correctly represent the contents of your Model table in the database. Model.Length
should not be a decimal, but a string, thus representing the structure of your database Model
table
The neat solution would be to change the Length column in your database from string to value-with-precision (whatever database you are using). If you can't change the structure of the Model
table you database, you should change your Model class such that it represents your model:
class Model
{
public string Description {get; set;}
public string Length {get; set;}
private static IFormatProvider spanishCulture = CultureInfo.CreateSpecificCulture("es-ES");
[NotMapped]
public decimal LengthInMeters
{
get {return Decimal.Parse(this.Length, spanishCulture);}
set {this.Length = value.ToString(spanishCulture); }
}
}
This would also solve the problem of the unknown unit of length (m? cm? inch?)
An even cleaner solution, where you let your Model
class exactly represent the database table, would be to create a SpanishModel
class and create extension functions to convert from Model
to SpanishModel
and back
// model represents exactly database table:
class Model
{
public string Description {get; set;}
public string Length {get; set;}
}
class SpanishModel
{
public string Description {get; set;}
public decimal Length {get; set;}
}
// extension functions of model:
static class ModelExtensions
{
private static IFormatProvider spanishCulture = CultureInfo.CreateSpecificCulture("es-ES");
public static SpanishModel AsSpanishModel(this Model model)
{
return new SpanishModel()
{
Description = model.Description,
Length = Decimal.Parse(model.Length, spanishCulture);
}
}
public static Model AsModel(this SpanishModel model)
{
return new Model()
{
description = model.Description,
Length = model.Length.ToString(spanishCulture),
};
}
public static IEnumerable<SpanishModel> AsSpanishModels(this IEnumerable<Model> models)
{
return models.Select(model => model.AsSpanishModel();
}
public static IEnumerable<SpanishModel> AsModels(this IEnumerable<SpanishModel> models)
{
return models.Select(model => model.AsModel();
}
}
Usage:
IEnumerable<SpanishModel> requestedModels = myDbContext.Models
.Where(model => model.Description == ...)
.AsSpanishModels();
See Extension Functions Demystified
If you really want to hide the fact that SpanishModels are not part of your database, consider extending your DbContext class:
static class MyDbContextExtensions
{
public static IQueryable<SpanishModel> SpanishModel(this MyDbContext dbContext)
{
return dbContext.Models.AsSpanishModels();
}
}
usage:
using (var myDbContext = new MyDbContext(...))
{
IQueryable<SpanishModel> tallSpanishModels = myDbContext.SpanishModels
.Where(model => model.Length > 1.85M);
foreach (SpanishModel tallModel in tallSpanishModels)
{
Console.WriteLine($"{tallModel.Description} has a length of {tallModel.Length}";
}
}
You almost can't see any difference between other DbSets
of your DbContext
and your SpanishModel
. Come to think of it, I think this is the neatest solution.