同一个表和外键上的两个主键

时间:2016-08-02 09:54:52

标签: c# entity-framework

我有两张桌子,其中一张与其他桌子有关。 第一个表

 public class Text
  {
    [Key]
    [Column(Order = 1)]
    [Required]
    [MinLength(7)]
    [MaxLength(7)]
    public string Fieldname { get; set; }

    [Key]
    [Column(Order = 2)]
    [Required]
    public virtual Language Language { get; set; }

    [MaxLength(50)]
    [MinLength(1)]
    [Required]
    public string Description { get; set; }
  }

和第二个表:

public class Language
  {
    [Key]
    [Required]
    [MaxLength(2), MinLength(2)]
    public string Code { get; set; }
    [Required]
    public string Country { get; set; }
  }

种子数据如下:

context.Language.AddOrUpdate(
        new Language() {Code = "DE", Country = "German"},
        new Language() {Code = "EN", Country = "English"});

context.Text.AddOrUpdate(
        new Text { Fieldname = "TEXT001", Description = "Server", Language = context.Language.First(e => e.Code == "EN") },
        new Text { Fieldname = "TEXT001", Description = "Server", Language = context.Language.First(e => e.Code == "DE") }
      );

我更新数据库并收到以下错误消息:

  

System.Data.Entity.Core.UpdateException:更新条目时发生错误。有关详细信息,请参阅内部异常---> System.Data.SqlClient.SqlException:违反PRIMARY KEY约束' PK_dbo.Texts'。无法在对象' dbo.Texts'中插入重复键。重复键值为(TEXT001)。

有什么问题?

2 个答案:

答案 0 :(得分:1)

我认为您不能使用导航属性定义PK的一部分,因此EF只会忽略Column属性上的KeyLanguage属性,最终只会PK Fieldname

您需要明确包含FK字段,如下所示:

public class Text
{
    [Key]
    [Column(Order = 1)]
    [Required]
    [MinLength(7)]
    [MaxLength(7)]
    public string Fieldname { get; set; }

    [Key]
    [Column(Order = 2)]
    [Required]
    [MaxLength(2), MinLength(2)]
    public string LanguageCode { get; set; }

    [ForeignKey("LanguageCode")]
    public virtual Language Language { get; set; }

    [MaxLength(50)]
    [MinLength(1)]
    [Required]
    public string Description { get; set; }
}

答案 1 :(得分:1)

@IvanStoev的回答是正确的。但我想展示另一种选择。我建议使用Fluent API映射您的类。相信我,这样,你的模型将更加清晰,映射也很容易理解。

文字模型及其映射:

public class Text
{
    public string FieldName { get; set; }  
    public string LanguageCode { getl set; } // Add this foriegn key property
    public string Description { get; set; }

    // Navigation properties
    public virtual Language Language { get; set; }
}

internal class TextMap
    : EntityTypeConfiguration<Text>
{
    public TextMap()
    {
        // Primary key
        this.HasKey(m => new { m.FieldName, m.LanguageCode });

        this.Property(m => m.FieldName)
                .HasMaxLength(7)
                .IsFixedLength();

        this.Property(m => m.LanguageCode)
                .HasMaxLength(2)
                .IsFixedLength();

        // Properties
        this.Property(m => m.Description)
            .IsRequired()
            .HasMaxLength(50);                      

        // Relationship mappings
        this.HasRequired(m => m.Language)
            .WithMany()
            .HasForeignKey(m => m.LanguageCode)
            .WillCascadeOnDelete(false);
    }
}

语言模型及其映射:

public class Language
{
    public string Code { get; set; }
    public string Country { get; set; }
}

internal class LanguageMap
    : EntityTypeConfiguration<Language>
{
    public LanguageMap()
    {
        // Primary key
        this.HasKey(m => m.Code);

        this.Property(m => m.Code)
                .HasMaxLength(2)
                .IsFixedLength();

        // Proeprties
        this.Property(m => m.Country)
            .IsRequired();
    }
}

然后你应该覆盖DbContext的OnModelCreating方法并将你的映射添加为:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new TextMap());
    modelBuilder.Configurations.Add(new LanguageMap());
}