How to add the support for structured annotations to the EF Core SqlServer target builder?

.net annotations entity-framework entity-framework-core entity-framework-core-migrations

Question

It is easy to add plain string annotations to the EF model with HasAnnotation method that accept object type of argument, but trying to add structured annotations you will get errors on build migration:

        modelBuilder.Entity<Group>().HasAnnotation($"{GetType().FullName}.Constraint3", new ValueTuple<string,string>( "aaa", "bbb" ));

The current CSharpHelper cannot scaffold literals of type 'System.ValueTuple`2[System.String,System.String]'. Configure your services to use one that can.

        modelBuilder.Entity<Group>().HasAnnotation($"{GetType().FullName}.Constraint2", new[] { "aaa", "bbb" });

The current CSharpHelper cannot scaffold literals of type 'System.String[]'. Configure your services to use one that can.

Do we have a way to inject a method to the target builder that would help to serialize structured annotations?

Why I would need it? Just trying to collect all database meta in one place. And meta is usually structured info.

1
1
1/11/2018 9:28:10 PM

Accepted Answer

As far as I understand (there is not much if any at all information about that), the idea is to use simple name / value pairs, where the values are primitive types (string, int, decimal, DateTime etc. plus enums) and names form the structure. All EF Core annotations follow that principle. For instance, Name: "SqlServer:ValueGenerationStrategy" Type: SqlServerValueGenerationStrategy etc.

Probably the easiest is to simply follow that convention. But anyway, the responsible service is ICSharpHelper - UnknownLiteral method. And the default implementation is in CSharpHelper class.

So you can derive from it, override the UnknownLiteral method and do your own (pre)processing there:

using Microsoft.EntityFrameworkCore.Design.Internal;

public class MyCSharpHelper : CSharpHelper
{
    public override string UnknownLiteral(object value)
    {
        // Preprocess the value here...
        return base.UnknownLiteral(value);
    }
}

then replace the standard service with yours:

using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.DependencyInjection;

public class MyDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
    {
        services.AddSingleton<ICSharpHelper, MyCSharpHelper>();
    }
}
2
1/12/2018 6:30:58 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow