【问题标题】:Many to one migrations fails on foreign key long外键长的多对一迁移失败
【发布时间】:2017-04-12 03:53:41
【问题描述】:

我有 2 个模型:

public class Text
{
    public long Id { get; set; }
    public string Text { get; set; }
}

public class User
{
    public int Id { get; set; }
    public ICollection<Text> Texts { get; set; }
}

我的用户模型是这样的

e.HasMany(o => o.Texts).WithOne().HasForeignKey(d => d.Id).IsRequired();

当我尝试运行时:

dotnet ef 迁移添加

我收到此错误:

具有外键属性 {'Id' : long} 无法定位主 key {'Id' : int} 因为它不兼容。配置主体 键或一组兼容的外键属性 关系。

更新:

新模型应该能够拥有表格文本的集合,例如:

public class Customer
{
    public int Id { get; set; }
    public ICollection<Text> Texts { get; set; }
}

....

e.HasMany(o => o.Texts).WithOne().HasForeignKey(d => d.Id).IsRequired();

【问题讨论】:

  • 一个是int,另一个是long
  • 是的,但我怎么能说关键属性类型是长的
  • 有类似的情况。为了将来参考,[此链接] (entityframeworkcore.com/knowledge-base/48998620/…) 有所帮助。从流行的答案...[Column(TypeName = "int")] public long Id { get; set; } 应该可以工作。

标签: c# entity-framework


【解决方案1】:

使用 EF Core 时遇到类似问题,但不想在依赖实体 Text 中包含(在我的类中等效)UserId,只是为了让 EF 满意。终于发现可以替换关系中使用的主键(UserId) 使用 HasPrincipalKey()

    modelBuilder.Entity<User>()
        .HasMany(t => t.Texts)
        .WithOne()
        .HasPrincipalKey(u => u.Text);

【讨论】:

    【解决方案2】:

    在 EF 上下文配置中,特别是在 HasForeignKey() 中,您应该指定 Text 模型上的哪个属性应该是指向 User 模型的外键?

    既然User模型的主键是int,那么从Text指向User的外键自然也应该是int

    我认为您犯的错误是您将Text 的PK 配置为关系Text -> User 的FK。尝试将您的 Text 模型更改为:

    public class Text
    {
       public long Id { get; set; }
       public string Text{ get; set; }
       public int UserId { get; set; }
    }
    

    你的配置:

    e.HasMany(o => o.Texts).WithOne().HasForeignKey(d => d.UserId).IsRequired();
    

    【讨论】:

    • 如果我添加一个新模型:具有相同的客户,ICollectionTexts 的集合。你的答案不起作用,有没有一种解决方案可以让我改变“自然”的行为?
    • 您能否详细说明我的答案是如何起作用的以及您添加了什么模型?也许还有一些代码?不可能改变自然行为,因为外键是应该唯一标识另一个表中的行的东西。如果该行的标识(主键)是int,那么您可以用来标识该行的唯一数据类型是int,否则将无法识别它。
    • 我仍然不确定您要达到的目标。 Customer 模型与 User 模型相同。除此之外,您还没有解决外键问题。如果 1 个 User 可以有超过 1 个 Text,即使您有相同类型的 ID,如果没有 Text 上的附加 (UserId) 属性,也无法实现这种关系。
    • 哦,现在我明白了,非常感谢您的解释!
    【解决方案3】:

    首先,请更改您的模型命名,

    public class Text
    {
        public long Id { get; set; }
        public int UserId { get; set; }// add a foreign key that could point to User.Id
        public string Body { get; set; }//you cannot have a string property called "Text".
        public virtual User Owner { get; set; }
    }
    public class User
    {
        public int Id { get; set; }
        public virtual ICollection<Text> Texts { get; set; } = new HashSet<Text>();
    }
    
    builder.Entity<Text>(table =>
            {
                table.HasKey(x => x.Id);
    
                table.HasOne(x => x.User)
                .WithMany(x => x.Texts)
                .HasForeignKey(x => x.UserId)
                .HasPrincipalKey(x => x.Id)//<<== here is core code to let foreign key userId point to User.Id.
                .OnDelete(DeleteBehavior.Cascade);
            });
    

    我们必须弄清楚引用哪个键的原因是因为有多个主键。我在 MSDN 看到过一次,但是找不到了。

    你可以为外键使用影子属性,现在看起来很流行。

    public class Text
    {
        public long Id { get; set; }
        public string Body { get; set; }
        public virtual User Owner { get; set; }
    }
    public class User
    {
        public int Id { get; set; }
        public virtual ICollection<Text> Texts { get; set; } = new HashSet<Text>();
    }
    
    builder.Entity<Text>(table =>
            {
                table.HasKey(x => x.Id);
    
                // Add the shadow property to the model
                table.Property<int>("UserId");
    
                table.HasOne(x => x.User)
                .WithMany(x => x.Texts)
                .HasForeignKey("UserId")//<<== Use shadow property
                .HasPrincipalKey(x => x.Id)//<<==point to User.Id.
                .OnDelete(DeleteBehavior.Cascade);
            });
    

    【讨论】:

      【解决方案4】:

      您可以简单地删除所有迁移或产生该 Id 的迁移,删除数据库(如果它很小或没有数据)并添加一个干净的迁移

      【讨论】:

        【解决方案5】:

        我在一对一的关系中也面临同样的问题。如果您在一对一的关系中遇到问题。然后试试这个:

        
            public partial class document
            {
                public document()
                {
                    groups = new group();
                }
                 public int? group_id { get; set; }
                 public virtual group groups { get; set; }
            }
            
            [Table("group")]
            public class group
            {
                [Key]
                [Column("group_id")]
                public int group_id { get; set; }
        
                
                [ForeignKey(nameof(group_id))]
                public virtual document document { get; set; }
            }
        

        每个文档都有一个组。所以,我们可以考虑这些设置。

        modelBuilder.Entity<group>().HasOne(a => a.document)
                    .WithOne(y => y.groups).HasForeignKey<document>(b => b.group_id);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-20
          • 1970-01-01
          • 2022-11-30
          • 1970-01-01
          • 2020-10-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多