Reputation: 18645
I'm using scaffolded entities with Entiy Framework Core 2.1. The 3rd party database uses some unser defined data types (that I didn't know about) that don't seem to be recognized by EF-Core.
According to The Fluent API HasColumnType Method and Reverse Enginer: Support type aliases (user-defined data types) this should work. However, I'm not sure if only for precofigured/built-in types like Name
or any types.
The engine generates this
entity.Property(e => e.Status).HasColumnType("Enumeration");
for Enumeration:smallint
but translating it to SQL doesn't work well so it throws a SqlException
Class 16 byte LineNumber 1 int Message "Type Enumeration is not a defined system type." string Number 243 int Procedure "" string Server "..." string Source ".Net SqlClient Data Provider" string State 2 byte
Is there a way to define other user defined data types or fix this in any other way?
Upvotes: 3
Views: 2171
Reputation: 18645
I've found a workaround.
At the and of the OnModelCreating
method I'll just remove the generated ColumnType
annotation:
modelBuilder
.Entity(typeof(MyEntity))
.Property(nameof(MyEntity.Status))
.Metadata
.RemoveAnnotation("Relational:ColumnType");
A small helper function that goes over all entities and removes that annotation automatically from all properties that have it should be enough for now.
public static class ModelBuilderExtensions
{
public static ModelBuilder RemoveAnnotations<TDbContext>(this ModelBuilder modelBuilder, TDbContext context, string name, IList<string> values) where TDbContext : DbContext
{
var bindingFlags =
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.DeclaredOnly;
var entityMethod =
typeof(ModelBuilder)
.GetMethods()
.Single(m =>
m.Name == nameof(ModelBuilder.Entity) &&
m.GetGenericArguments().Length == 1 &&
m.GetParameters().Length == 0
)
.GetGenericMethodDefinition();
foreach (var contextProperty in typeof(TDbContext).GetProperties(bindingFlags))
{
var entity =
contextProperty
.PropertyType
.GetGenericArguments()
.SingleOrDefault();
if (entity is null)
{
continue;
}
// Only the generic overload returns properties. The non-generic one didn't work.
var generitcEntityMethod = entityMethod.MakeGenericMethod(entity);
foreach (var property in entity.GetProperties(bindingFlags))
{
var entityTypeBuilder = (EntityTypeBuilder)generitcEntityMethod.Invoke(modelBuilder, null);
if (entityTypeBuilder.Metadata.FindProperty(property) is null)
{
continue;
}
var annotation =
entityTypeBuilder
.Property(property.Name)
.Metadata
.FindAnnotation(name);
if (values.Contains(annotation?.Value))
{
entityTypeBuilder
.Property(property.Name)
.Metadata
.RemoveAnnotation(name);
}
}
}
return modelBuilder;
}
}
Usage:
modelBuilder.RemoveAnnotations(this, "Relational:ColumnType", new[] { "Enumeration" });
Upvotes: 1