Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Many to one migrations fails on foreign key long

I have 2 models:

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

My model build on user is that

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

When I try to run:

dotnet ef migrations add

I get this error:

with foreign key properties {'Id' : long} cannot target the primary key {'Id' : int} because it is not compatible. Configure a principal key or a set of compatible foreign key properties for this relationship.

UPDATE:

It should be able for new models to have a collection of the table Texts like:

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();
like image 339
Domi Avatar asked Nov 28 '16 12:11

Domi


People also ask

How do I fix foreign key constraint failure?

The error message itself showing there is a foreign key constraint error, which means you are deleting a parent table where the child table contains the Primary table identifier as a foreign key. To avoid this error, you need to delete child table records first and after that the parent table record.

What problems do foreign keys introduce?

Foreign key problems. Many database users encounter foreign key errors, often due to referential integrity problems. A foreign key might point to data that no longer exists, or the foreign key's data type doesn't match the primary key data type, eroding referential integrity.

What is not true about foreign key?

Q 26 - Which of the following is not true about a FOREIGN KEY constraint? A - It is a referential integrity constraint. B - It establishes a relationship between a primary key or a unique key in the same table or a different table. C - A foreign key value cannot be null.

Why foreign keys are not redundant?

Essentially, primary and foreign keys are used as a way to constrain or link related data in a database. This ensures that data remains consistent and that the database contains no redundant data. For example, if you delete a table (or even a row in a table) that other tables rely on, the redundant data is removed.


3 Answers

Had similar problem using EF Core but didn't want to include the (equivalent in my class) UserId on the dependent entity Text, just to make happy EF. Finally found that you can replace the primary key used in the relationship (UserId) using HasPrincipalKey()

    modelBuilder.Entity<User>()
        .HasMany(t => t.Texts)
        .WithOne()
        .HasPrincipalKey(u => u.Text);
like image 113
Riga Avatar answered Sep 28 '22 01:09

Riga


In the EF context configuration, specifically in the HasForeignKey() you are supposed to specify Which property on the Text model should be the foreign key that points to the User model?

Since User model's primary key is an int, the foreign key pointing from Text to User should naturally also be an int.

I think the mistake you've made is that you are configuring the PK of Textto also be the FK for the relationship Text -> User. Try to change your Text model to :

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

And your configuration to:

e.HasMany(o => o.Texts).WithOne().HasForeignKey(d => d.UserId).IsRequired();
like image 44
valorl Avatar answered Sep 28 '22 01:09

valorl


Firstly, change your Model naming please,

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

the reason we have to figure out which key is referred is because of multiple primary keys. I saw it once in MSDN, but cannot find it back.

You can use shadow properties for foreign keys, it looks popular now.

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);
        });
like image 25
Dongdong Avatar answered Sep 28 '22 01:09

Dongdong