ef4 poco double/float dbtype mapping - entity-framework

I have an exiting database with couple of float/double fields, I chose to use EF4.1 for my DAL/ORM, but I am having problems when reading/saving data to his type of fields. There is no model, just using model builder to configure the entities.
First there was a rounding problem, I think typical of floating point math, so because all of the precision were already set as 2 decimals, I switched to using decimal type on the c# (EF) side, but now when I am trying to get an entity, I get an exception saying I am in trouble.
The 'xxxkg' property on 'YYY' could not be set to a 'Double' value.
You must set this property to a non-null value of type 'Decimal'.
xxxkg is float null on the database, and the value is 10 in the specific case, and in the class it is
public decimal? xxxkg { get; set; }
The question is how to deal with dbtype float/double variables with EF4 (poco)?

You cannot define your property as decimal if it is double in database. EF does not type conversion (and doesn't allow you defining your own) and double value cannot be assigned to decimal variable so populating your class from read record will fail. You must use double.

Related

Entity Framework Core 6 - System.Data.SqlTypes.SqlNullValueException: Data is Null. This method or property cannot be called on Null values

I'm using EF Core 6 on .NET 6.0 and am looking at this error:
System.Data.SqlTypes.SqlNullValueException: Data is Null. This method or property cannot be called on Null values
The error message should indicate that EF Core is trying to read a value for a required property, i.e. a property which should never have null value in the database, but instead the underlying data reader reports null value for that property in some record(s).
Entity Framework Core: `SqlNullValueException: Data is Null.` How to troubleshoot?
Disabling nullable reference type the error disappears and everything works well.
Is it possible to investigate exactly what field is causing this issue, debugging the code doesn't give me more details.
Is there some technique to get the name of the offending field or fields?
Visually I didn't find any discrepancy between the database and the model
Check the document related with Nullable reference types
In a nullable aware context:
A variable of a reference type T must be initialized with non-null,
and may never be assigned a value that may be null.
A variable of areference type T? may be initialized with null or
assigned null, but is required to be checked against null before
de-referencing.
assuming an entity:
public class SomeEntity   
{   
[Key]     
public int Id { get; set; }       
  public string Name { get; set; }        
public string Prop { get; set; }    
}
If you enabled nullable reference type, Name and Prop property would never be assigned with null
Assuming the Db:
When you read data from db and assign the null value in db to your entity,you would get the error you've shown
Is it possible to investigate exactly what field is causing this issue
All properties type of T instead of T? in your entity with the column could be null in db would cause this issue
Both Disabling nullable reference type and Setting your property which may have null value in db with T? would solve the issue.
For example,in my case,the Name column and Prop column could be null in db,when you check your entity, Name and Prop property should be type of string? instead of string .
yes, this is the cause.
But my question (maybe is not so clear, it's my falut) is about how to get some sort of notification from the debbugger, the call stack, or from a verbose output, an indicatin of what field has null value
It's not so easy to verify manually because my entity are a customization of a the aspnet identity database
E.G: calling _userManager.FindByNameAsync i got this error
Apparently i've filled all nullable values but maybe the error is caused by other related entity e.g Roles, Claims, and so on
So i'd like to get a clear indication about what is the first field(if there are more) that has caused the problem.
If possible of course!

EF Core: filter on converted column [duplicate]

Suppose I want to enhance a model like
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
so that I use a complex object for Address:
public class Person
{
public string Name { get; set; }
public Address Address { get; set; }
}
EF Core is quite nice in allowing this with the HasConversion feature:
modelBuilder.Entity<Person>
.Property(p => p.Address)
.HasConversion(addr => addr.ToString(), str => Address.FromString(str));
I even tested and this works in queries with == operator: The following will successfully convert to SQL
var whiteHouse = Address.Parse("1600 Pennsylvania Avenue NW");
var matches = from person in people
where person.Address == whiteHouse
select person;
However, suppose I want to string.Contains on the string version of Address, something like
var search = "1600";
var matches = from person in people
where person.Address.ToString().Contains(search)
select person;
This will fail to convert. Is there any feature of EF Core to map the ToString() method or otherwise map a complex object that converts to a string / VARCHAR so that I can write a query like this?
The problem with EF Core value converters and LINQ queries is that the LINQ query is against the CLR entity property, hence the CLR type rather than the provider type. This is partially mentioned under currently Limitations of the value conversion system section of the EF Core documentation:
Use of value conversions may impact the ability of EF Core to translate expressions to SQL. A warning will be logged for such cases. Removal of these limitations is being considered for a future release.
So having query expression against the CLR type combined with the inability to translate custom methods is causing your issue. Technically it's possible to add custom method/property translation, but it's quite complicated because requires a lot of non user friendly infrastructure plumbing code, which makes practically unusable in real life application development.
In this particular case though, you know that the provider type is string, and the database table values are generated by ToString method. So you just need to let the query use the provider type. And you can do that by using cast operator.
Normally C# compiler won't allow you to cast known object type to another known object type if there is no conversion between them. But you can trick it by using the "double cast" technique by first casting to object and then to the desired type. Fortunately EF Core translator supports such casts and properly (sort of) translates them to SQL. By sort of I mean it emits unnecessary (redundant) CAST inside the query, but at least it translates and executes server side.
With that being said, the solution for your example is
where ((string)(object)person.Address).Contains(search)
As a default behavior, EF Core use Server-side evaluation, EF Core try to translate your expression to standard DB provider T-SQL code (based on selected DB provider)
you expression can't translate to T-SQL code and the DB provider can't handle it (Because the logic you write in the overridden version of ToString() is in your C# code and is unknown to the database provider)
You should force EF Core to use client-side evaluation by fetching all data to memory and then query on the loaded entities, something like this:
var search = "1600";
var matches = from person in people.ToList()
where person.Address.ToString().Contains(search)
select person;
Note that fetching all data to memory in huge databases have performance impacts and use client-side evaluation carefully.

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)]

entity framework "composite" property?

I am using EF 4.1, code first and want a property on a customer entity built up of a constant string value and the customerId zero padded to act as a customer reference.
I might be being a bit daft but am struggling to work out how I can achieve this without
A) having to savechanges twice, once to get the Id then set my reference and save again
B) having a partial Customer class that simply provides a getter returning constant + CustomerId.Tostring("000000")
Is this "doable" with code first?
If you can change the database I would make a computed column for this. Thus, you leave it to the database to generate a reference value and it will also be available to other consumers of the database (if any).
Your Customer class will have a property like CustomerReference (string) that maps to the computed column and that is configured to have DatabaseGeneratedOption.Computed which will cause EF to read the value after inserting an object.

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