Getting Precision And Scale In Entity Framework Core - entity-framework-core

Is there a way in Entity Framework Core 3 to read the precision and scale specified on a column?
For example if I have:
[Column(TypeName = "numeric(5, 2)")]
Is there a way in code to access the precision value of 2 and scale value of 5?
I can access the "numeric(5, 2)" as a string but don't want to have it to parse that to get the 2 and 5.
The code I am using is this:
myModel.FindEntityType(myEntityType).FindProperty(myPropertyName).GetRelationalTypeMapping();
I can actually see whilst debugging, the scale and precision specified in the Parameters collection returned by the above code but as Parameters is protected there is no way to access it in code.
This was possible in Entity Framework (.Net Framework) using the EdmProperty class.
Thanks
Tristan.

Related

EF Core 6 Decimal precision warning

After upgrading to EF Core 6, I have this annoying warning here when adding a migration:
No store type was specified for the decimal property '{property}' on entity type '{entityType}'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'.
which is defined here: https://github.com/dotnet/efcore/blob/main/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs
I am not sure to understand the purpose of this warning because on entities with the tag [Keyless] as they do not live in the database. Also adding an attribute such as [Column(TypeName = "decimal(28, 6)")] doesn't seem to clear the warning on keyless entities.
Apparently there's a new attribute for EF Core 6:
using Microsoft.EntityFrameworkCore;
...
[Precision(18, 2)]

How get EF GetValidationErrors to validate decimal magnitude?

Currently, in EF 6.1.3, if a decimal is declared in Code First with HasPrecision(6,2) and the value is 1234567.0 then GetValidationErrors does not detect any error, and SaveChanges fails.
I don't want to custom validate every entity being written to the database and would like to somehow get GetValidationErrors to validate the magnitude of a decimal about to be written to the database that has precision declared.
Is this possible? May be I'm missing something...Thx!
You change your property precision for example in your DbContext like that:
modelBuilder.Entity<AnEntity>().Property(e => e.property).HasPrecision(14, 12);
You can also disabling the automatic validation on Save and create your custom data annotation for the validation:
MyDbContext.Configuration.ValidateOnSaveEnabled = false;
You can create your custom EF validator as described in my post below:
Entity Framework UI Validation using WinForms

How to control JSON.NET serialization of System.Data.Spatial.DbGeometry

I have a DB First Entity Framework 5 Data Access Layer that is mapped to a table containing a SQL geometry type field called CenterCoordinate. The resulting entity contains this:
public System.Data.Spatial.DbGeometry CenterCoordinate { get; set; }
My client javascript requests the API and only accepts JSON. I then use the Asp.net Web API to serve this using the default formatter (JSON.NET). In the API controller the field has a long list of properties including an XCoordinate and a YCoordinate.
In the client the JSON only contains this:
Geometry: Object
CoordinateSystemId: 3498
WellKnownBinary: null
WellKnownText: "POINT (6438089.715 1801515.828)"
I really don't want to have to parse out the WellKnownText to get to the values of X and Y.
So the question is how can I control the serialisation/de-serialisation of System.Data.Spatial types to/from JSON such that I get something more useful? How does the JSON.net formatter know what to include/exclude?
Note: I really don't want decorate the entity with attributes as these will be lost each time I regenerate the model from the database (I have no idea why we can't add attributes to model fields through VS2012 and have it remember them after a regeneration). So can this be with partial classes or overriding the formatter?
Thanks, Matt
Unfortunately, you're more or less stuck parsing the WellKnownText field if you want to manipulate the coordinates with Javascript.
Geometry is a SQLSpatial type that is saved to a database via the WKT field, so that's why your DbGeometry type is converting the JSON to that format.
If it makes you feel any better, it's causing me just as much of a hassle right now.
Edit: These resources might help a bit:
GeoJSON has a structure much more similar to SpatialSQL:
http://www.geojson.org/geojson-spec.html
https://github.com/Esri/geojson-utils/blob/master/src/jsonConverters.js
This is a solution used to serialize/deserialize DbGeo types as JSON:
http://www.arcgis.com/home/item.html?id=6d28a606369c43fd9a6f929541ae7c93

Slow linq query when looking for char(1) datatype using contains

I've got an old database with a char(1) Status column. I'm using code first and entity framework 4.3.1 to interact with my database. My Status column in my code first class is defined as follows:
[Column(TypeName = "char")]
public string Status { get; set; }
I'm writing a linq query to fetch all items with a Status of one of several values. The code looks something like this (although it's been simplified):
List<string> statusList = new List<string>() {"N","H","P"};
...
var entries = (from t in context.MyTable where statusList.Conains(t.Status)).ToList();
...
The SQL thats generated prefixes all the Status values with N making the query quite slow.
WHERE ([Extent1].[Status] IN (N'N', N'P', N'P'))
It seems to be because it's comparing unicode with non unicode so it can't use the index on the Status column.
I've had similar problems before in other linq queries, but I thought they were solved by putting [Column(TypeName = "char")] on the property.
Does anyone know how I prevent SQL from putting those N's in front of all my Status values? I tried making statusList a List of char, but then I needed to change the definition of the Status column to char in code first, but that threw errors.
Thanks
David
Are you on .NET Framework 4? I think this was fixed in EF5 core libraries shipped with .NET Framework 4.5. Here is a connect bug for this: http://connect.microsoft.com/VisualStudio/feedback/details/709906/entity-framework-linq-provider-defaulting-to-unicode-when-translating-string-contains-to-like-clause The connect bug also contains a workaround - use EntityFunctions.AsNonUnicode() function to force strings not to be Unicode which may be helpful if you can't move to .NET Framework 4.5

How to tell entity framework how to save instances of a custom type (that can be stored as a scalar)

One of my entity classes would be possible to store in a sql server
database as a BIGINT. My question is: How do I get a Entity Framework
context to know how to store and retrieve instances of my entity class?
More detail. I'm using Noda Time, which can represent a (much) wider range of
dates than can SQL or .NET datetime (AND it's a dessert topping). My Entity Class, Happening, is a wrapper around NodaTime's
Instant class. I can set a Happening from a long, and get a long from
a happening with methods like .SetFromLong(long instant) and .ToLong().
Currently I have my model working, saving classes that contain
properties of the dot net DateTime type. If instead I want to use properties
of my custom type "Happening", how do I tell Entity Framework how to save those?
If I'm reading this article about Modeling and Mapping am I on the
right track or missing something simpler?
http://msdn.microsoft.com/en-us/library/bb896343.aspx
I'm using entity framework 4.
What i recommend doing is adding 2 properties on your entity a NodaTime and a long, and exclude your NodaTime property using [NotMapped] in your EF model, then in your getter/setter update the long.
ie
public class MyEntity{
public long TimeAsLong{get;set;}
[NotMapped]
public Happening {
get{
return new Happening().SetFromLong(TimeAsLong);
}
set {
TimeAsLong = value.ToLong();
}
}
}
The effect of this will be that the long is stored in the db but you can access it on the class via NodaTime