外键长的多对一迁移失败

Posted

技术标签:

【中文标题】外键长的多对一迁移失败【英文标题】: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; 应该可以工作。 【参考方案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);

【讨论】:

以上是关于外键长的多对一迁移失败的主要内容,如果未能解决你的问题,请参考以下文章

spring boot jpa中的多对一映射中的外键未在子表中更新

hibernate之多对一单向关联

hibernate之多对一单向关联

hibernate学习四 hibernate关联关系映射

关于JPA一对一,一对多(多对一),多对多的详解

映射关系模板--一对一, 一对多