【问题标题】:EF 6 Relationship: One or more validation errors were detected during model generationEF 6 关系:在模型生成过程中检测到一个或多个验证错误
【发布时间】:2016-10-10 12:34:34
【问题描述】:

我一直在努力找出我认为相对简单的关系映射(一对多)。

让我们回顾一下模型中的内容:

内容外部链接

public class ContentExternalLink
{
    public ContentExternalLink()
    {
        ContentTagAssignments = new List<ContentTagAssignment>();
    }

    [Key]
    public string LinkId { get; set; }
    public string LinkTypeId { get; set; }
    public string LinkTitle { get; set; }
    public string LinkUrl { get; set; }
    public string LinkSource { get; set; }
    public string LinkPhoneNumber { get; set; }
    public DateTime LinkDate { get; set; }
    public DateTime LinkCreatedDate { get; set; }
    public DateTime LinkModifiedDate { get; set; }
    [ScriptIgnore]
    public virtual ICollection<ContentTagAssignment> ContentTagAssignments { get; set; }
}

ContentTagAssignmnent

public class ContentTagAssignment
{
    public ContentTagAssignment()
    {
        this.ContentExternalLink = new ContentExternalLink();
    }

    [Key]
    public string TagId { get; set; }
    [Key]
    public string ArticleId { get; set; }
    public bool IsPrimary { get; set; }
    public DateTime CreatedDate { get; set; }
    [ScriptIgnore]
    public virtual ContentExternalLink ContentExternalLink { get; set; }
}

现在进入映射:

ContentExternalLinkMap

public class ContentExternalLinkMap : EntityTypeConfiguration<ContentExternalLink>
{
    public ContentExternalLinkMap()
    {
        this.ToTable("content_external_link", "dbo");

        this.HasKey(c => c.LinkId);

        this.Property(c => c.LinkId).HasColumnName("link_id");
        this.Property(c => c.LinkTypeId).HasColumnName("link_type_id");
        this.Property(c => c.LinkTitle).HasColumnName("link_title");
        this.Property(c => c.LinkUrl).HasColumnName("link_url");
        this.Property(c => c.LinkSource).HasColumnName("link_source");
        this.Property(c => c.LinkPhoneNumber).HasColumnName("link_phone_number");
        this.Property(c => c.LinkDate).HasColumnName("link_date");
        this.Property(c => c.LinkCreatedDate).HasColumnName("link_created_date");
        this.Property(c => c.LinkModifiedDate).HasColumnName("link_modified_date");
    }
}

ContentTagAssignmnetMap

public class ContentTagAssignmentMap : EntityTypeConfiguration<ContentTagAssignment>
{
    public ContentTagAssignmentMap()
    {
        this.ToTable("content_tag_assignment", "dbo");

        this.HasKey(t => new {t.TagId, t.ArticleId});

        this.Property(t => t.TagId).HasColumnName("tag_id");
        this.Property(t => t.ArticleId).HasColumnName("article_id");
        this.Property(t => t.IsPrimary).HasColumnName("is_primary_tag");
        this.Property(t => t.CreatedDate).HasColumnName("created_date");


        this.HasOptional(t => t.ContentExternalLink)
            .WithMany(t => t.ContentTagAssignments)
            .HasForeignKey(t => new {t.TagId, t.ArticleId});
    }
}

这种关系肯定很奇怪,因为 LinkId 会与 ContentTagAssignment 中的 ArticleId 匹配。

我在 ContentTagAssignmentMap 中尝试了以下方法:

    //this.HasOptional(t => t.ContentExternalLink)
//    .WithMany(t => t.ContentTagAssignments)
//    .HasForeignKey(t => t.ContentExternalLink);

this.HasOptional(x => x.ContentExternalLink)
    .WithMany(x=>x.ContentTagAssignments)
    .Map(x => x.MapKey("LinkId").HasColumnAnnotation("LinkId","ArticleId",null));

//this.Map(m =>
//    {
//        m.Properties(x => x.ArticleId);
//        m.ToTable("content_tag_assignment");
//    })
//    .Map(p =>
//    {
//        p.Properties(x => x.ContentExternalLink.LinkId);
//        p.ToTable("ContentExternalLink");
//    });

注释的关系不起作用。一个有效的(因为它在初始页面加载时不会失败)。但是,当我尝试从 ContentExternalLink 访问列表时,出现以下错误:{"Invalid column name 'LinkId'.\r\nInvalid column name 'LinkId'."}

所以我更迷茫了……

问题

基本上,并非每个 ContentExternalLink 都会为其分配标签。但是,如果 ContentExternalLink 有 ContentTagAssignments,我应该能够获得它们的列表。此外,TagId 和 ArticleId 是字符串(guid)。

有人有什么建议吗?

谢谢!

【问题讨论】:

  • 你展示的两个模型都是一样的 (ContentTagAssignmnent) :)
  • @StephenMuecke doh!感谢您告诉我,我已经用真实模型更新了 ContentExternalLink 模型。
  • @GertArnold 我不确定该帖子如何适用于我的问题。我已经用更多信息更新了我的帖子。
  • 看看你的ContentTagAssignment构造函数。

标签: c# asp.net-mvc entity-framework asp.net-mvc-5 entity-relationship


【解决方案1】:

ivan stoev的cmets之后,我看到这里唯一的错误是当外键也是主键时设置可选(not nullable

所以映射将是:

public class ContentTagAssignmentMap : EntityTypeConfiguration<ContentTagAssignment>
{
    public ContentTagAssignmentMap()
    {
        this.ToTable("content_tag_assignment", "dbo");

        this.HasKey(t => new { t.TagId, t.ArticleId });

        this.Property(t => t.TagId).HasColumnName("tag_id");
        this.Property(t => t.ArticleId).HasColumnName("article_id");
        this.Property(t => t.IsPrimary).HasColumnName("is_primary_tag");
        this.Property(t => t.CreatedDate).HasColumnName("created_date");


        this.HasRequired(t => t.ContentExternalLink)
            .WithMany(t => t.ContentTagAssignments)
            .HasForeignKey(t => t.ArticleId)
            .WillCascadeOnDelete(false);
    }
}

以下是您的模型的工作示例:

class Program
{
    static void Main(string[] args)
    {
        var ctx = new Context();
        ctx.Database.Delete();
        ctx.Database.CreateIfNotExists();

        Console.ReadKey();
    }
}

public class Context : DbContext
{
    public Context():base ("Teste")
    {

    }

    public DbSet<ContentExternalLink> ContentExternalLinks { get; set; }
    public DbSet<ContentTagAssignment> ContentTagAssignments { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new ContentExternalLinkMap());
        modelBuilder.Configurations.Add(new ContentTagAssignmentMap());

        base.OnModelCreating(modelBuilder);
    }

}

public class ContentExternalLink
{
    public ContentExternalLink()
    {
        ContentTagAssignments = new List<ContentTagAssignment>();
    }

    [Key]
    public string LinkId { get; set; }
    public string LinkTypeId { get; set; }
    public string LinkTitle { get; set; }
    public string LinkUrl { get; set; }
    public string LinkSource { get; set; }
    public string LinkPhoneNumber { get; set; }
    public DateTime LinkDate { get; set; }
    public DateTime LinkCreatedDate { get; set; }
    public DateTime LinkModifiedDate { get; set; }

    public virtual ICollection<ContentTagAssignment> ContentTagAssignments { get; set; }
}

public class ContentTagAssignment
{
    public ContentTagAssignment()
    {
        this.ContentExternalLink = new ContentExternalLink();
    }

    [Key]
    public string TagId { get; set; }
    [Key]
    public string ArticleId { get; set; }
    public bool IsPrimary { get; set; }
    public DateTime CreatedDate { get; set; }

    public virtual ContentExternalLink ContentExternalLink { get; set; }
}

public class ContentExternalLinkMap : EntityTypeConfiguration<ContentExternalLink>
{
    public ContentExternalLinkMap()
    {
        this.ToTable("content_external_link", "dbo");

        this.HasKey(c => c.LinkId);

        this.Property(c => c.LinkId).HasColumnName("link_id");
        this.Property(c => c.LinkTypeId).HasColumnName("link_type_id");
        this.Property(c => c.LinkTitle).HasColumnName("link_title");
        this.Property(c => c.LinkUrl).HasColumnName("link_url");
        this.Property(c => c.LinkSource).HasColumnName("link_source");
        this.Property(c => c.LinkPhoneNumber).HasColumnName("link_phone_number");
        this.Property(c => c.LinkDate).HasColumnName("link_date");
        this.Property(c => c.LinkCreatedDate).HasColumnName("link_created_date");
        this.Property(c => c.LinkModifiedDate).HasColumnName("link_modified_date");
    }
}

public class ContentTagAssignmentMap : EntityTypeConfiguration<ContentTagAssignment>
{
    public ContentTagAssignmentMap()
    {
        this.ToTable("content_tag_assignment", "dbo");

        this.HasKey(t => new { t.TagId, t.ArticleId });

        this.Property(t => t.TagId).HasColumnName("tag_id");
        this.Property(t => t.ArticleId).HasColumnName("article_id");
        this.Property(t => t.IsPrimary).HasColumnName("is_primary_tag");
        this.Property(t => t.CreatedDate).HasColumnName("created_date");


        this.HasRequired(t => t.ContentExternalLink)
            .WithMany(t => t.ContentTagAssignments)
            .HasForeignKey(t => t.ArticleId)
            .WillCascadeOnDelete(false);
    }
}

这是上面代码的结果:

【讨论】:

  • 抱歉,我撤回了建议的更改。 FK 总是在many 一侧,所以它不可能是LinkId
  • 它是可选侧的键,它引用了您将使用的多侧。您需要引用 ContentExternalLink 的 ContentTagAssignment 上的 FK,即 LinkId
  • 正确。但是在提供ContentTagAssignment 实体的OP 中没有LinkId 属性,并且根据OP 的解释,LinkId 将与 ContentTagAssignment 中的 ArticleId 匹配,所以我的假设是基于该声明(并且答案中提到)。
  • 没有看到 ArticleId 会匹配 LinkId。我的错,对不起
【解决方案2】:

您的实体模型/实现存在两个问题。

让我们从更简单的开始(在Gert Arnold's comment 中提到)。根据经验,您永远不应该在构造函数(或内部的任何其他位置)内初始化单个导航属性,因为这会破坏 EF 延迟加载行为。

很快,只需删除

this.ContentExternalLink = new ContentExternalLink();

来自ContentTagAssignment 类构造函数的行。

现在是主要问题。 EF6 仅支持引用主体端的 PK(主键)的 FK(外键)关系。这意味着您不能在 ContentTagAssignment 实体中使用复合键 (TagId, ArticleId) 来引用 ContentExternalLink 实体的单个 PK (LinkId),因为您尝试使用 HasForeignKey(t =&gt; new {t.TagId, t.ArticleId}) 调用进行设置。这两列形成依赖端的PK(ContentTagAssignment)这一事实与关系无关。没有其他选择 - 您必须选择两个字段之一。根据 LinkId 将与 ContentTagAssignment 中的 ArticleId 匹配,这应该是 ArticleId 字段。

如果我猜对了,直接替换

this.HasOptional(t => t.ContentExternalLink)
    .WithMany(t => t.ContentTagAssignments)
    .HasForeignKey(t => new {t.TagId, t.ArticleId});

this.HasRequired(t => t.ContentExternalLink)
    .WithMany(t => t.ContentTagAssignments)
    .HasForeignKey(t => t.ArticleId);

并且(连同构造函数修改)应该可以解决问题。

请注意,我还将HasOptional 更改为HasRequired,因为ArticleId 字段是PK 的一部分,因此无论如何都不允许null 值。

【讨论】:

    【解决方案3】:

    我认为问题在于您尝试使用外键但未指明正确的连接。

    您需要做的是向 ContentTagAssignment 添加一个 LinkId 字段,这是您应该使用的实际外键并加入该字段:

    this.HasOptional(t => t.ContentExternalLink)
    .WithMany(t => t.ContentTagAssignments)
    .HasForeignKey(t => t.LinkId);
    

    原因是您告诉它去查找一个在 ContentExternalLink 中不存在的键(tagId、ArticleId)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-04
      • 2014-03-07
      • 1970-01-01
      • 2013-02-13
      • 1970-01-01
      • 2011-02-06
      相关资源
      最近更新 更多