Home > Blockchain >  Error when trying to configure 1-to-1 relationship. The property 'Id' cannot be part of a
Error when trying to configure 1-to-1 relationship. The property 'Id' cannot be part of a

Time:08-12

I've an entity which has a FK on another entity. Both of them have Id's as PK and they are auto-generated. When I try to configure FK like this :

public void Configure(EntityTypeBuilder<Document> builder)
{
    builder.HasOne<Price>(x => x.Price)
        .WithOne()
        .HasForeignKey<Price>(x => x.Id)
        .OnDelete(DeleteBehavior.Restrict);
}

Goal is, in Document table I should have FK on Price. It's 1-to-1.

public abstract class EntityBase
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), Column(Order = 0)]
    public Guid Id { get; set; }
}

public class Price : EntityBase
{
    [MinLength(1), MaxLength(255)]
    public string Type { get; set; } = null!;
}

public class Document : EntityBase
{
    public string Name { get; set; } = null!;

    public virtual Price? Price { get; set; }
}

When I try to add migration, I get this error :

The property 'Id' cannot be part of a foreign key on 'Price' because it has a store-generated value and is contained in the key {'Id'} defined on a base entity type 'EntityBase'. Configure 'Id' with 'ValueGeneratedNever' or define the foreign key on 'Price' instead.

I understand that I can define Id in Price but I do not want that. Is there any other way?

CodePudding user response:

I would strongly recommend using a seperate foreign key

  public class Price : EntityBase
{
    [MinLength(1), MaxLength(255)]
    public string Type { get; set; } = null!;
    public virtual Document? Document { get; set; }
}

public class Document : EntityBase
{
    public string Name { get; set; } = null!;
    public Guid? PriceId { get; set; }
    public virtual Price? Price { get; set; }
}

public void Configure(EntityTypeBuilder<Document> builder)
    {
        builder.HasOne<Price>(x => x.Price)
            .WithOne(x => x.Document)
            .HasForeignKey<Document>(x => x.PriceId)
            .OnDelete(DeleteBehavior.Restrict);
    }

Technically you could only have a navigation property in Price to Document in the following manner.

public class Price : EntityBase
{
    [MinLength(1), MaxLength(255)]
    public string Type { get; set; } = null!;
    public virtual Document Document { get; set; }
}

With that this works.

  builder.HasOne<Price>(x => x.Price)
        .WithOne(x => x.Document)
        .HasForeignKey<Price>(x => x.Id)
        .OnDelete(DeleteBehavior.Restrict);

Do note that by not having a seperate foreign key your document id and price id will be the same. You will however run into trouble if you are not creating both of them in the same operation and relating them.

The value of 'Price.Id' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known

or

Cannot insert the value NULL into column 'Id', table 'DataContext.dbo.Prices'; column does not allow nulls

So basically something like below will not work.

var document = new Document() { Name = "John Doe" };
db.Documents.Add(document);
var price = new Price() { Type = "Price 1" };
db.Prices.Add(price);
db.SaveChanges();

But doing exactly the following will:

var document = new Document() { Name = "John Doe" };
var price = new Price() { Type = "Price 1" };
document.Price = price;
db.Documents.Add(document);
db.SaveChanges();

Thus I would advise against declaring the Price.Id as a foreign key, while it is possible working with that structure will be a pain.

  • Related