DevTekVE
DevTekVE

Reputation: 193

Unable to determine the relationship represented by navigation property ASP.NET core 2.0 Entity Framework

I am currently developing an ASP.NET app that uses EntityFramework, for the given code

public partial class EnumMeta : Meta
{
    public EnumMeta()
    {
        this.Messages = new HashSet<MessageMeta>();
    }

    public bool IsFlag { get; set; }

    public virtual ICollection<MessageMeta> Messages { get; set; }
}

public partial class MessageMeta : Meta
{
    public MessageMeta()
    {
        this.Enums = new HashSet<EnumMeta>();
        this.Receiver = new HashSet<Module>();
        this.Sender = new HashSet<Module>();
    }

    public int MsgId { get; set; }

    public virtual ICollection<EnumMeta> Enums { get; set; }
    public virtual ICollection<Module> Receiver { get; set; }
    public virtual ICollection<Module> Sender { get; set; }
}

I am getting an error:

Unable to determine the relationship represented by navigation property 'EnumMeta.Messages' of type 'ICollection'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

This code was auto-generated by EntityFramework using a WPF project and then the models were taken to an ASP.NET core 2.0 project to do a "code-first" approach to the database.

I have already tried setting up [ForeignKey("MessageMeta")] above public virtual ICollection<MessageMeta> Messages { get; set; } without any positive solution.

Upvotes: 18

Views: 40322

Answers (1)

David Liang
David Liang

Reputation: 21476

As what I commented earlier that there are many differences between Entity Framework and Entity Framework Core 2.0, I don't think you can just take the models generated from Entity Framework and run Code First with Entity Framework Core 2.0.

From the models described, it looks like MessageMeta and EnumMeta has many-to-many relationship.

As today, Entity Framework Core 2.0 still doesn't support many-to-many without the intermediate class. So in order to do many-to-many in EF Core 2.0, you need the intermediate class.

MessageMeta

using System.Collections.Generic;

namespace DL.SO.MessageEnum.Web.UI.Models
{
    public class MessageMeta
    {
        public int MsgId { get; set; }

        public List<MessageEnum> EnumMetas { get; set; }
    }
}

EnumMeta

using System.Collections.Generic;

namespace DL.SO.MessageEnum.Web.UI.Models
{
    public class EnumMeta
    {
        public int EnumId { get; set; }
        public bool IsFlag { get; set; }

        public List<MessageEnum> MessageMetas { get; set; }
    }
}

MessageEnum (or you can call it EnumMessage) - intermediate model

namespace DL.SO.MessageEnum.Web.UI.Models
{
    public class MessageEnum
    {
        public int MessageMetaId { get; set; }
        public MessageMeta MessageMeta { get; set; }

        public int EnumMetaId { get; set; }
        public EnumMeta EnumMeta { get; set; }
    }
}

DbContext

using Microsoft.EntityFrameworkCore;

namespace DL.SO.MessageEnum.Web.UI.Models
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options): base(options) { }

        public DbSet<MessageMeta> Messages { get; set; }
        public DbSet<EnumMeta> Enums { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<MessageMeta>()
                .HasKey(x => x.MsgId);

            modelBuilder.Entity<EnumMeta>()
                .HasKey(x => x.EnumId);

            modelBuilder.Entity<MessageEnum>()
                .HasKey(x => new { x.MessageMetaId, x.EnumMetaId });
            modelBuilder.Entity<MessageEnum>()
                .HasOne(x => x.MessageMeta)
                .WithMany(m => m.EnumMetas)
                .HasForeignKey(x => x.MessageMetaId);
            modelBuilder.Entity<MessageEnum>()
                .HasOne(x => x.EnumMeta)
                .WithMany(e => e.MessageMetas)
                .HasForeignKey(x => x.EnumMetaId);
        }
    }
}

appsettings.json

{
  "ConnectionStrings": {
    "AppDbConnection": "Data Source=.\\SQLEXPRESS;Initial Catalog=SO.MessageEnum;Integrated Security=True;MultipleActiveResultSets=False;"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  }
}

Startup

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using DL.SO.MessageEnum.Web.UI.Models;
using Microsoft.EntityFrameworkCore;

namespace DL.SO.MessageEnum.Web.UI
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            string dbConnectionString = Configuration.GetConnectionString("AppDbConnection");

            services.AddDbContext<AppDbContext>(options =>
                options.UseSqlServer(dbConnectionString)
            );

            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Commands to run on Package Manager Console

Add-Migration Init
Update-Database

Generated database

enter image description here

Upvotes: 24

Related Questions