EF CORE How to Change NVACHAR to VARCHAR - entity-framework-core

In Entity Framework 6.X It was possible to change the default database type by doing this:
modelBuilder.Properties<string>().Configure(c => c.HasColumnType("varchar"));
In EF Core how can i do that?
The method Properties() doesn´t exists.

Since EF Core 6, based on github repository of entity framework (see here) :
previous versions of EF Core (before EF Core 6) require that the
mapping for every property of a given type is configured explicitly
when that mapping differs from the default. This includes "facets"
like the maximum length of strings and decimal precision, as well as
value conversion for the property type.
In the class that inherits from DbContext override ConfigureConventions
protected override void ConfigureConventions(
ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder
.Properties<string>()
.AreUnicode(false)
.HaveMaxLength(1024);
}
Thus all string properties can be configured to be ANSI (instead of Unicode) and have a maximum length of 1024, hence mapping string to nvarchar changes to varchar when migrations are applied to the database.

Related

Entity Framework Core set column to nvarchar(max) with code first

I am using Entity Framework Core 7.0.0 and in my OnModelCreating method I am trying to specify a column to be of type nvarchar(max).
In EF6 (not Core!), we were able to do something like:
modelBuilder.Entity<Log>().Property(p => p.Errors).IsMaxLength();
However, I am not able to figure this out in EF Core. Is there something similar available in EF Core that I am missing?
I know that it would normally default all properties of type string to nvarchar(max) but I am overriding DbContext's ConfigureConventions with the following, to default all string to 50 characters:
configurationBuilder.Properties<string>().HaveMaxLength(50);
With help of [Column] data annotation:
[Column(TypeName = "nvarchar(MAX)")]
With help of Fluent API:
entity.Property(p => p.Errors)
.HasColumnName("YourColumnName")
.HasColumnType("nvarchar(MAX)");
HasColumnName: the HasColumnName attribute is applied to a property to specify the database column that the property should map to when the entity's property name and the database column name differ.
HasColumnType: the HasColumnType method is applied to a property to specify the data type of the column that the property should map to when the type differs from convention.

Entity framework 6 - Access the entity object during valueConverter

I have a project with Entity Framework Core 6 for SQL. it's a large project with a lot of entities and properties (and yes, a lot...). All properties are defined not nullable (bool, int etc.) because the SQL database tables all are not-nullable columns also. All good.
But now this project must works with an Oracle database server, and here are tables with nullable columns which not match with the not nullable entities (Oracle EF cannot match nullabe column with a not-nullable directly).
Changing all columns with not nullable with default value isn't possible. And making the entities nullable give us a lot of (test) work because it hits the logical part of code.
So, my challenge is to find a solution that nullable table columns can set not-nullable entity properties with a value or default and without changing the entity set of code.
Using the ValueConverter is the first solution but it isn't possible because a null value will never be passed to a value converter.
So I try it with a shadow property. I have this:
entityTypeBuilder.Ignore(property.Name);
entityTypeBuilder.Property<int?>($"_Nullable_{property.Name}")
.HasConversion<NullableIntConverter >()
.HasColumnName(oracleColumn.ColumName);
Here I ignore the original property for EF, then I add a shadow property with converter for the nullable type (<int?>). This is the valueConverter:
internal class NullableIntConverter : ValueConverter<int, int?>
{
public NullableIntConverter()
: base(
_convertToEntityProviderExpression,
_convertToDbProviderExpression)
{
}
private static readonly Expression<Func<int?, int>> _convertToDbProviderExpression = x =>
x.GetValueOrDefault();
private static readonly Expression<Func<int, int?>> _convertToEntityProviderExpression = x => x;
}
This works, a nullable column set the shadow property but not the original property.
The solution will be setting the original property during ValueConverter. But because of static it isn't really possible. Or maybe someone have a solution here? If I have the entity object, I can use reflection for setting the original property.
I hope that someone have a tip for a solution?

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

NPGSQL date time array

I'm attempting to use the timestamp[] field type in Postgres with NPGSQL, so that I can use the DateTime[] type in my Entity Framework models.
I've added this to my EF code first model.
[Column("HostUnavailableDates", TypeName = "timestamp[]")]
public DateTime[] HostUnavailableDates { get; set; }
I've created a migration and the database has updated successfully.
However I am getting this error when executing transactions with the model.
Message: System.InvalidOperationException : The property 'HostApplication.HostUnavailableDates' could not be mapped, because it is of type 'DateTime[]' which is not a supported primitive type or a valid entity type. Either explicitly map this property, or ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I've followed this answer which does not use any type of ignoring of the property. Is there something I need to do for the DateTime type in addition to what I'm currently doing?
Is DateTime in fact not supported at all in this case?
I'm using EF Core.
I'm assuming you're using Entity Framework 6.x. If that's the case, then arrays simply aren't supported, you'll have to switch to Entity Framework Core.

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