【问题标题】: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播种代码优先数据库会导致错误 --> 无法添加实体类型“$name”的种子实体,因为它设置了导航“$name”
【发布时间】:2020-03-03 08:04:00
【问题描述】:

我对代码优先方法和 .NET Core 3 EF 非常陌生。经过多年良好的旧数据库项目和纯 SQL 后,昨天才开始。出于测试目的,我想在我的数据库中预先填充一堆用于测试目的的条目。但是,这似乎不像我预期的那样工作。我已经移动了一些东西,但错误消息并没有消失:

无法添加实体类型“SourceColumnNaming”的种子实体 因为它设置了导航“SourceColumn”。播种 您需要将相关实体种子添加到的关系 'SourceColumn' 并指定外键值 {'SourceColumnID'}。 考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来 查看涉及的属性值。

这是我的代码:

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;
        }
    }
}

这就是我的数据对象的样子:

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
    });
}

知道如何摆脱错误消息吗?

【问题讨论】:

    标签: c# .net-core entity-framework-core


    【解决方案1】:

    我在播种数据库时使用它取得了巨大的成功。它添加完整的“对象树”,使用现有的外键或在数据库中找不到时添加它们。

    public void AddCascadingObject(object rootEntity) //Place inside DbContext.cs
    {
        ChangeTracker.TrackGraph(
            rootEntity, 
            node => 
                node.Entry.State = !node.Entry.IsKeySet ? EntityState.Added : EntityState.Unchanged
        );
    }   
    

    【讨论】:

    • 你能举一个实际的例子如何使用它吗?
    • @AndréReichelt 这有帮助吗?
    • EFCore 中似乎没有 Seed 方法。如果我将您的代码复制粘贴到我的课程中,它会说没有找到方法,这可能会被覆盖。还是我错过了什么?
    • 似乎我错了;(docs。从 2.1 开始,您实际上在 OnModelCreating 中做种子。
    【解决方案2】:

    我能够解决问题。播种时,似乎无法通过仅将数据条目添加到彼此的导航属性来“自动绑定”数据条目。相反,您不能设置导航属性,而是单独定义每个外键 ID 字段。为此,我必须首先将各种 ID 字段添加到我的数据模型中。此外,不能通过添加两个 [Key] 注释来声明复合键(不再)。相反,您必须为此目的使用流体 api。

    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        InitializeKeys(modelBuilder);
    
        SeedData(modelBuilder);
    }
    
    /// <summary>
    /// Initializes compound keys for all entities.
    /// </summary>
    /// <param name="modelBuilder">The <see cref="ModelBuilder" /> reference from the <see cref="OnModelCreating(ModelBuilder)"/> method.</param>
    private void InitializeKeys(ModelBuilder modelBuilder) {
        modelBuilder.Entity<SourceColumnNaming>()
            .HasKey(scn => new { scn.SourceColumnID, scn.Language });
    
        modelBuilder.Entity<ViewerColumn>()
            .HasKey(vc => new { vc.ViewerRoleID, vc.SourceColumnID });
    }
    
    /// <summary>
    /// Pre-fills table with required data
    /// </summary>
    /// <param name="modelBuilder">The <see cref="ModelBuilder" /> reference from the <see cref="OnModelCreating(ModelBuilder)"/> method.</param>
    private void SeedData(ModelBuilder modelBuilder) {
        // Viewer role
        var viewerRole = new ViewerRole() {
            ID = 1,
            Name = "Testrolle",
            Description = "Dies ist eine Testrolle"
        };
    
        modelBuilder.Entity<ViewerRole>().HasData(viewerRole);
    
        // Source columns
        int columnCount = 1;
    
        List<SourceColumn> sourceColumns = new List<SourceColumn>();
        List<SourceColumnNaming> sourceColumnNamings = new List<SourceColumnNaming>();
        List<ViewerColumn> viewerColumns = new List<ViewerColumn>();
    
        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() {
                SourceColumnID = col.ID,
                Language = "de-DE",
                Text = MapPropertyName(prop.Name)
            };
    
            var viewerColumn = new ViewerColumn() {
                SourceColumnID = col.ID,
                ViewerRoleID = viewerRole.ID,
                IsEditable = false,
                Order = columnCount,
            };
    
            sourceColumns.Add(col);
            sourceColumnNamings.Add(colNaming);
            viewerColumns.Add(viewerColumn);
    
            columnCount++;
        }
    
        modelBuilder.Entity<SourceColumnNaming>().HasData(sourceColumnNamings.ToArray());
        modelBuilder.Entity<SourceColumn>().HasData(sourceColumns.ToArray());
        modelBuilder.Entity<ViewerColumn>().HasData(viewerColumns.ToArray());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多