4

I am using a T4 template slightly modified from the one proposed in this answer to generate typescript interfaces from my EF POCOs.

The EF Core POCOs were generated database first, and some of the database columns have default values. These are correctly mapped by the EF generator into my context, e.g. .HasDefaultValueSql("0");

I'm a little confused about how to go about accessing the default value for a given EF class, i had thought GetValueOrDefault might do the trick but that's just giving the default value for the .net type.

I see there are some other solutions out there for getting this working but i can't seem to find one that yet works with ASP .Net Core.

Ideally, i would like to know how to determine if a property has a default EF value from it's MemberInfo, as the following line from the T4 template is generating the property descriptions it would be the easiest to modify that to output a default value for the TypeScript def.

foreach (MemberInfo mi in GetInterfaceMembers(t))
{
    sb.AppendFormat("  {0}: {1};\n", mi.Name, GetTypeName(mi));
}
Community
  • 1
  • 1
  • It would be much easier if you'll set the default value using a data-annotation attribute instead. Something like `[DefaultValue("0")]`. You can then easily access it using `MemberInfo.CustomAttributes` – haim770 Oct 06 '16 at 11:55
  • Do you have access to the source `DbContext` inside the template? – Ivan Stoev Oct 06 '16 at 11:56
  • @haim770 i am generating the classes from a database that already exists, i don't own the db and if it changes i want to be able to regenerate without examining the defaults manually –  Oct 06 '16 at 12:33
  • @IvanStoev sure i guess i can get access to thedbcontext inside the template, i have a mixture of EF and non EF classes that i am generating but i could easily split that into 2 templates –  Oct 06 '16 at 12:34

1 Answers1

2

In case you have access to the generated DbContext, you can use the metadata provided by the DbContext.Model instead of reflection.

For instance:

foreach (var type in db.Model.GetEntityTypes())
{
    foreach (var property in type.GetProperties())
    {
        var defaultValue = property.Relational().DefaultValue;
    }
}

There are also a lot of useful methods like IModel.FindEntityType, IEnityType.FindProperty etc.

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • I'm struggling to get it to reference the extension methods from RelationalMetadataExtensions in the T4 template, this code works fine in a class but i'm getting `'IProperty' does not contain a definition for 'Relational'` error in the text template. any ideas? –  Oct 06 '16 at 13:52
  • 1
    Ah i got it i had to reference the assembly dll, and then the namespace afterwards too. –  Oct 06 '16 at 13:57
  • Indeed. Assemby: `Microsoft.EntityFrameworkCore.Relational`, Namespace: `Microsoft.EntityFrameworkCore` – Ivan Stoev Oct 06 '16 at 13:59
  • Hmm, it's returning null for everything even though some of them definitely have default values in the context –  Oct 06 '16 at 14:36
  • Aha, using sql server so it's `property.SqlServer().DefaultValueSql;` –  Oct 06 '16 at 14:38
  • You nailed it :) Happy coding! – Ivan Stoev Oct 06 '16 at 14:40
  • Thanks for the help, much appreciated. –  Oct 06 '16 at 14:41