1

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.

Roman Pokrovskij
  • 9,449
  • 21
  • 87
  • 142

1 Answers1

2

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>();
    }
}
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • When I was composing question I had tryed POCO with the same result (error)... But now I will experiment little bit more with it. – Roman Pokrovskij Jan 12 '18 at 21:46
  • 1
    Hmm, I've tried it before posting and it worked. With your first sample, the code was something like `if (value is ValueTuple vt) return $"new ValueTuple({Literal(vt.Item1)}, {Literal(vt.Item2)})";` And it generated correct `HasAnnotation` in migration `designer.cs` file. Make sure your service is called by putting temporarily `throw new Exception("Blah");` at the beginning of the overridden method. Tested with EFC 2.0.1 if that matters. – Ivan Stoev Jan 12 '18 at 22:55
  • 1
    yep this works and very surprised way (directly insert the text to migration sources)... I got a great feeling of "wizard of liquid code". thank you very much. at least migrations in ef core done flexible way (I deeply dissatisfied with EF core logging particularly and EF core DI "container only" manner generally). – Roman Pokrovskij Jan 12 '18 at 23:52
  • Ivan, may be I can ask you to tell your ideas on those quesions (first is continuation of attempts to reuse EF COre metamodel ): 1) https://stackoverflow.com/questions/48242973/ef-core-how-to-build-model-without-context-how-to-get-the-same-conventionset-u 2) https://stackoverflow.com/questions/47744989/how-to-update-the-entity-before-delete-on-savecontext – Roman Pokrovskij Jan 13 '18 at 18:28
  • 1
    Hi @Roman, Sure, I will when have some time. But note that I'm not participating in EF Core development, so all my posts are based on documentation, experimenting and exploring the source code :) – Ivan Stoev Jan 13 '18 at 18:43
  • You are right I had a hope that you are insider. But you are so deep in it that should write a book. Or a boilerplate of high configurable EF usage (per-context-logging + model-extension + standard sql/dml modification)... I have first only ( https://stackoverflow.com/questions/43680174/entity-framework-core-log-queries-for-a-single-db-context-instance/47490737#47490737 ), and a half of second (after your help). – Roman Pokrovskij Jan 13 '18 at 19:01