Seeding code-first database leads to an error --> The seed entity for entity type '$name' cannot be added because it has the navigation '$name' set

.net-core c# entity-framework-core

Question

I'm very new to the code-first approach and .NET Core 3 EF. Just started yesterday after many years of the good old database project and pure SQL. For testing purposes, I wanted to prefill my database with a bunch of entries for testing purposes. However, that doesn't seem to work as I expected. I already moved some stuff around, but the error message doesn't go away:

The seed entity for entity type 'SourceColumnNaming' cannot be added because it has the navigation 'SourceColumn' set. To seed relationships you need to add the related entity seed to 'SourceColumn' and specify the foreign key values {'SourceColumnID'}. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the involved property values.

Here's my code:

using DE.ZA.MobilePickingApp.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace DE.ZA.MobilePickingApp.Database {
    public class MpaContext : DbContext {
        public DbSet<ViewerRole> ViewerRoles { get; set; }
        public DbSet<ViewerColumn> ViewerColumns { get; set; }
        public DbSet<SourceColumn> SourceColumns { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder options) {
            options.UseSqlServer("Server=vWebDev01;Database=MPA;Integrated Security=True;");
            //options.UseLazyLoadingProxies();
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            // ======= DATA SEEDING =======

            int columnCount = 1;

            List<SourceColumn> sourceColumns = new List<SourceColumn>();
            List<SourceColumnNaming> sourceColumnNamings = new List<SourceColumnNaming>();
            List<ViewerColumn> viewerColumns = new List<ViewerColumn>();

            // Source columns
            foreach (var prop in typeof(PickingListEntry).GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)) {
                var col = new SourceColumn() {
                    ID = columnCount,
                    Key = prop.Name,
                    Type = (Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType).Name
                };

                var colNaming = new SourceColumnNaming() {
                    SourceColumn = col,
                    Language = "de-DE",
                    Text = MapPropertyName(prop.Name)
                };

                var viewerColumn = new ViewerColumn() {
                    ID = columnCount,
                    DataColumn = col,
                    IsEditable = false,
                    Order = columnCount
                };

                sourceColumns.Add(col);
                sourceColumnNamings.Add(colNaming);
                viewerColumns.Add(viewerColumn);

                columnCount++;
            }

            modelBuilder.Entity<SourceColumnNaming>().HasData(sourceColumnNamings);
            modelBuilder.Entity<SourceColumn>().OwnsOne(sc => sc.DefaultNames).HasData(sourceColumns);
            modelBuilder.Entity<ViewerColumn>().HasData(viewerColumns);

            // Viewer role
            modelBuilder.Entity<ViewerRole>().HasData(
                new ViewerRole() {
                    ID = 1,
                    Name = "Testrolle",
                    Description = "Dies ist eine Testrolle",
                    ViewerColumns = viewerColumns
                }
            );
        }

        private string MapPropertyName(string propName) {
            // ...
            return propName;
        }
    }
}

And this is how my data objects look like:

public class SourceColumn {
    [Key, Column(Order = 1)]
    public int ID { get; set; }

    [Required]
    public string Key { get; set; }

    [Required]
    public string Type { get; set; }

    [Required]
    public List<SourceColumnNaming> DefaultNames { get; set; } = new List<SourceColumnNaming>();
}

public class SourceColumnNaming {
    [Key]
    public SourceColumn SourceColumn { get; set; }

    [Key, MaxLength(5)]
    public string Language { get; set; }

    public string Text { get; set; }
}

public class ViewerColumn {
    [Key, Column(Order = 1)]
    public int ID { get; set; }

    [Required]
    public virtual SourceColumn DataColumn { get; set; }

    public string CustomName { get; set; }

    public int Order { get; set; }

    public bool IsEditable { get; set; }
}

public class ViewerRole {
    [Key, Column(Order = 1), JsonIgnore]
    public int ID { get; set; }

    [Required]
    public string Name { get; set; }

    public string Description { get; set; }

    [JsonIgnore]
    public List<ViewerColumn> ViewerColumns { get; set; } = new List<ViewerColumn>();

    [NotMapped]
    public IEnumerable<Models.ClientColum> ClientColumns => ViewerColumns?.Select(vc => new Models.ClientColum() {
        Key = System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName(vc.DataColumn.Key),
        Sortable = true
    });
}

Any idea how I can get rid of the error message?

1
0
3/3/2020 8:04:00 AM

Popular Answer

I use this to great success when seeding databases. It addes the complete "object-tree", uses existing foreign-keys or adds them if the cannot be found in the database.

public void AddCascadingObject(object rootEntity) //Place inside DbContext.cs
{
    ChangeTracker.TrackGraph(
        rootEntity, 
        node => 
            node.Entry.State = !node.Entry.IsKeySet ? EntityState.Added : EntityState.Unchanged
    );
}   
1
3/3/2020 1:57:32 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