Data Annotations being ignored in .Net Core/EF Core Model (MySQL Backend)

asp.net-mvc asp.net-web-api entity-framework-core

Question

I have created a Web API using .Net Core 1.1 and EF Core. The backend is a MySQL Database, so I have included the "MySql.Data.EntityFrameworkCore": "7.0.6-IR31" dependency in the project.json file.

I have a simple model in my project. I am trying to map the columns in my model to the columns in an existing database. So I am using Data Annotations. I have this:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace PropWorxAPI.Models
    {
        [Table("files")]
        public partial class File
        {
            [Key]
            [Column("file_id")]
            public int FileId { get; set; }
            [Required]
            [Column("file_num")]
            [MaxLength(50)]
            public string FileNum { get; set; }
            [MaxLength(255)]
            public string Description { get; set; }
        }
    }

I want property FileId to map to field file_id in the database. However, when I run the project, it complains that there is no field FileId in the database. It's almost as if my column mapping annotations are being completely ignored. Any ideas? Thanks...

Just in case, I am including my project.json file below:

{
  "dependencies": {
    "MySql.Data.EntityFrameworkCore": "7.0.6-IR31",
    "Microsoft.AspNetCore.Mvc": "1.1.0",
    "Microsoft.AspNetCore.Routing": "1.1.0",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
    "Microsoft.Extensions.Configuration.Json": "1.1.0",
    "Microsoft.Extensions.Logging": "1.1.0",
    "Microsoft.Extensions.Logging.Console": "1.1.0",
    "Microsoft.Extensions.Logging.Debug": "1.1.0",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
    "Microsoft.NETCore.App": {
      "version": "1.1.0",
      "type": "platform"
    }
  },

  "tools": {
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.1.0-preview4-final"
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": [
        "dotnet5.6",
        "portable-net45+win8"
      ]
    }
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "**/*.cshtml",
      "appsettings.json",
      "web.config"
    ]
  },

  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}
1
2
1/13/2017 1:32:45 PM

Accepted Answer

I had this problem too, the only solution I could find was to use the fluent API to define mappings as opposed to annotations. E.g.

builder.Entity<Product>().ToTable("product").HasKey(m => m.Id);
builder.Entity<Product>().Property(p => p.DateAdded).HasColumnName("date_added");
builder.Entity<Product>().Property(p => p.ImageUrl).HasColumnName("image_url");

Hopefully support for annotations will be available soon.

2
1/21/2017 8:48:49 PM

Popular Answer

I wanted to avoid using the Fluent API because I preferred column mappings to be handled on the actual properties so I built my own column mapping using reflection.

See the code in the OnModelCreating function for the relevant parts.

Note I was using MySql and the code isn't 100% tested.

using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using MySQL.Data.EntityFrameworkCore.Extensions;
using System.Reflection;

namespace MyProject
{
    public class DatabaseContext : DbContext
    {
        private string _connectionString;

        public DbSet<Entity> Entities { get; set; }

        public DatabaseContext(string connectionString)
        {
            _connectionString = connectionString;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseMySQL(_connectionString);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // I couldn't get attribute mapping to work, so I
            // had to do the mapping programmatically myself.
            // Ideally we'd remove this code an rely on the
            // built-in code to handle it, but we need to wait
            // for MySql to support mapping in EF Core.

            var type = typeof(Entity);
            var properties = type
                .GetTypeInfo()
                .GetProperties(BindingFlags.Public |
                               BindingFlags.Instance | 
                               BindingFlags.DeclaredOnly);

            foreach (var property in properties)
            {
                System.Console.WriteLine(property.Name);

                var ignore = property.GetCustomAttribute<NotMappedAttribute>();
                if (ignore != null)
                {
                    modelBuilder
                        .Entity(type)
                        .Ignore(property.Name);

                    continue;
                }

                var column = property.GetCustomAttribute<ColumnAttribute>();

                if (column == null)
                {
                    modelBuilder
                        .Entity(type)
                        .Property(property.Name)
                        .HasColumnName(property.Name);

                    continue;
                }

                modelBuilder
                    .Entity(type)
                    .Property(property.Name)
                    .HasColumnName(column.Name);

            }
        }
    }
}


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