Since Entity Framework uses nvarchar(max)
as default for strings I would like to set something else as default.
https://dba.stackexchange.com/questions/48408/ef-code-first-uses-nvarcharmax-for-all-strings-will-this-hurt-query-performan
In Entity Framework 6.1.3 I could modify OnModelCreating(DbModelBuilder modelBuilder)
like this:
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
modelBuilder.Properties<DateTime>().Configure(c => c.HasPrecision(0));
modelBuilder.Properties<string>()
.Configure(s => s.HasMaxLength(256).HasColumnType("nvarchar"));
If I then modified a property with data annotations EF used these values instead, like this:
[MaxLength(128)]
public string Name { get; set; }
[Column(TypeName = "nvarchar(MAX)")]
[MaxLength]
public string Comment { get; set; }
However using Microsoft.EntityFrameworkCore.SqlServer 2.1.0
I cant do it like this and I can't use Conventions
either.
I could solve datetime
like this but if I try to do the same for strings the migration says type: "nvarchar(256)", maxLength: 128
if I use data annotations for example. How can I solve this?
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(DateTime)))
{
property.Relational().ColumnType = "datetime2(0)";
}
Update (EF Core 6.0+):
The ability to specify different type mapping defaults finally has been added in EF Core 6.0 via the so called Pre-convention model configuration, so the code now would be something like this:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
base.ConfigureConventions(configurationBuilder);
configurationBuilder.Properties<string>()
//.AreUnicode(false)
//.AreFixedLength()
.HaveMaxLength(256);
}
More examples are provided in the documentation link.
Important Note: However, as mentioned by @PeterB in comments and verified in EF Core issue tracker, for some reason this configuration has higher precedence (same as model builder fluent API), so you won't be able to override these "defaults" with data annotations (fluent configuration in OnModelCreating
will still do). So you might need to use the original approach below in case you rely on data annotations for overriding defaults.
Original:
There are several attributes indirectly affecting the column type of a string
property - MaxLength
(e.g. varchar(256)
vs varchar(MAX)
, IsUnicode
(e.g. nvarchar
vs varchar
) and IsFixedLength
(e.g. char
vs varchar
).
The current model API is inconsistent. The first is accessible through GetMaxLength
and SetMaxLength
, the second - via IsUnicode
and IsUnicode
, and there is no public model API for the third one (only fluent API).
So to set the MaxLength
you could use:
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(string)))
{
if (property.GetMaxLength() == null)
property.SetMaxLength(256);
}
which is not fully correct, because null
in this case has dual meaning - not specified and MAX
.
The correct way requires using EF Core internal API, which provides much more configuration methods, in particular allowing you to pass ConfigurationSource
enum value along with the attribute value. ConfigurationSource
enum values define the priority of the configuration - with Convention
being the lowest, then DataAnnotation
and finally Explicit
being the highest. The whole idea is that the lower priority configuration do not overwrite the configuration already set by a higher priority. All public fluent API use Explcit
, while in our case the Convention
perfectly fits (since we are simulating conventional default).
So if you accept the warning "This API supports the Entity Framework Core infrastructure and is not intended to be used directly from your code. This API may change or be removed in future releases.", add
using Microsoft.EntityFrameworkCore.Metadata.Internal;
and use
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(string)))
{
((Property)property).Builder
.HasMaxLength(256, ConfigurationSource.Convention);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With