Home > database >  EF Core Foreign Key: incompatible types
EF Core Foreign Key: incompatible types

Time:01-21

I looked through many similar questions, but I find no applicable solution.

I get the following error message during tests:

System.InvalidOperationException : The relationship from 'Product.FeatureType' to 'FeatureType.Product' with foreign key properties {'Type' : string} cannot target the primary key {'Id' : Guid} because it is not compatible. Configure a principal key or a set of compatible foreign key properties for this relationship.

The foreign key should be FeatureType's Type field.

This only happens, when I set the type of Product.Type as a string and as not as a Guid. But it should be a string, rather than a Guid. I do not understand at all what is the problem here. I do the project in a DB-first approach and the database can be created without a problem with SQL using this logic. I appreciate every help.

I have the following models:

public class Product : IDBModel
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }

    public DateTime SysStartTime { get; set; }
    public DateTime SysEndTime { get; set; }

    public FeatureType FeatureType { get; }
}

public class FeatureType : IDBModel
{
    public Guid Id { get; set; }
    public string Type { get; set; }
    public Guid? Description { get; set; }

    public DateTime SysStartTime { get; set; }
    public DateTime SysEndTime { get; set; }

    public TxtID TxtIDDescription { get; set; }
    public ICollection<Feature> Feature { get; }

    public ICollection<Product> Product { get; }
 }

And the following related context configuration:

public virtual DbSet<Product> Product { get; set; }
public virtual DbSet<FeatureType> FeatureType { get; set; }
...

modelBuilder.Entity<Product>(entity =>
        {
            entity.ToTable("Product", CoreSchema)
                .HasKey(k => new { k.Id }) 
                .HasName("PK_Product");
            entity.Property(a => a.Id).HasColumnName("id");
            entity.Property(a => a.Name).HasColumnName("name").IsRequired();
            entity.Property(a => a.Type).HasColumnName("type").HasMaxLength(50).IsRequired().IsUnicode(false);
            entity.Property(e => e.SysStartTime).HasColumnName("SysStartTime").ValueGeneratedOnAddOrUpdate();
            entity.Property(e => e.SysEndTime).HasColumnName("SysEndTime").ValueGeneratedOnAddOrUpdate();
            entity.HasOne(p => p.FeatureType)
                .WithMany(d => d.Product)
                .HasForeignKey(p => p.Type)
                .OnDelete(DeleteBehavior.Restrict);
        });

modelBuilder.Entity<FeatureAttributeSet>(entity =>
        {
            entity.ToTable("FeatureAttributeSet", "Core")
                .HasKey(e => new { e.Id })
                .HasName("PK_FeatureAttributeSet");

            entity.Property(e => e.Id).HasColumnName("id").IsRequired();
            entity.Property(e => e.AttributeSetId).HasColumnName("as_id").IsRequired();
            entity.Property(e => e.FeatureId).HasColumnName("feature_id").IsRequired();

            entity.Property(e => e.SysStartTime).ValueGeneratedOnAddOrUpdate();
            entity.Property(e => e.SysEndTime).ValueGeneratedOnAddOrUpdate();

            entity.HasOne(d => d.AttributeSet)
                        .WithMany(p => p.FeatureAttributeSet)
                        .HasForeignKey(d => d.AttributeSetId)
                        .OnDelete(DeleteBehavior.Cascade)
                        .HasConstraintName("FK_FeatureAttributeSet_AttributeSet");
            entity.HasOne(d => d.Feature)
                        .WithMany(p => p.FeatureAttributeSet)
                        .HasForeignKey(d => d.FeatureId)
                        .OnDelete(DeleteBehavior.Restrict)
                        .HasConstraintName("FK_FeatureAttributeSet_Feature");
        });

CodePudding user response:

The solution is to configure the PrincipalKey. The PrincipalKey will allow us to define the reference key with a unique restriction which will be the destination of the relationship. So you can use like this

 modelBuilder.Entity<Product>(entity =>
    {
            entity.ToTable("Product", CoreSchema)
                .HasKey(k => new { k.Id }) 
                .HasName("PK_Product");
            entity.Property(a => a.Id).HasColumnName("id");
            entity.Property(a => a.Name).HasColumnName("name").IsRequired();
            entity.Property(a => a.Type).HasColumnName("type").HasMaxLength(50).IsRequired().IsUnicode(false);
            entity.Property(e => e.SysStartTime).HasColumnName("SysStartTime").ValueGeneratedOnAddOrUpdate();
            entity.Property(e => e.SysEndTime).HasColumnName("SysEndTime").ValueGeneratedOnAddOrUpdate();
            entity.HasOne(p => p.FeatureType)
                .WithMany(d => d.Product)
                .HasPrincipalKey(p => p.Type)
                .HasForeignKey(p => p.Type)
                .OnDelete(DeleteBehavior.Restrict);
        });

CodePudding user response:

The foreign key that you specify in your model builder statement for the FeatureType of Product in .HasForeignKey(p => p.Type) must be the same type as the primary key of FeatureType. Because the Id property of FeatureType is a Guid, Type on Product must also be of type Guid to be used as the foreign key for the relationship with FeatureType.

Is there a reason that you can't change the type of the Type property to Guid?

  •  Tags:  
  • Related