Why does EF Core add the "RideId1" property to my model "RidePrice"? The error message from EF doesn’t provide much help: "The foreign key property ‘RidePrice.RideId1’ was created in shadow state because a conflicting property with the simple name ‘RideId’ exists in the entity type, but is either not mapped, is already used for another relationship, or is incompatible with the associated primary key type."
I don’t understand what conflict EF detected. Interestingly, even if I remove the "RideId" and "Ride" properties from "RidePrice", EF still adds a shadow property, just with a different name.
I assume that the shadow property is derived from "Waypoint", but I can’t figure out how to manage such a relationship.
Please help me understand. I don’t need this shadow property.
If the property that EF is adding is indeed necessary, I’m willing to include it in my model. However, I want to have a clear understanding of which relationship this property is used for.
Microsoft.EntityFrameworkCore.Design Version="7.0.5"
Microsoft.EntityFrameworkCore.Tools Version="7.0.5"
Npgsql.EntityFrameworkCore.PostgreSQL Version="7.0.4"
public class Ride
{
public Guid Id { get; set; }
public IReadOnlyList<Waypoint> Waypoints { get; set; }
public IReadOnlyList<RidePrice> Prices { get; set; }
}
public class Waypoint
{
public Guid Id { get; set; }
public Ride Ride { get; set; }
public NetTopologySuite.Geometries.Point Point { get; set; }
}
public class RidePrice
{
// Without own Id
public Guid RideId { get; set; }
public Ride Ride { get; set; }
public Guid FromId { get; set; }
public Waypoint From { get; set; }
public Guid ToId { get; set; }
public Waypoint To { get; set; }
public decimal Price { get; set; }
}
modelBuilder.Entity<Ride>(entityBuilder =>
{
entityBuilder.HasMany(x => x.Prices).WithOne(x => x.Ride)
.HasForeignKey(x => x.RideId)
.HasPrincipalKey(x => x.Id);
entityBuilder.HasMany(x => x.Waypoints).WithOne();
});
modelBuilder.Entity<Waypoint>(entityBuilder =>
{
entityBuilder.HasOne(x => x.Ride).WithMany(x => x.Waypoints);
});
modelBuilder.Entity<RidePrice>(entityBuilder =>
{
entityBuilder.HasKey(x => new { x.FromId, x.ToId });
entityBuilder.HasOne(x => x.From).WithMany().HasForeignKey(x => x.FromId);
entityBuilder.HasIndex(x => x.FromId);
entityBuilder.HasOne(x => x.To).WithMany().HasForeignKey(x => x.ToId);
entityBuilder.HasIndex(x => x.ToId);
entityBuilder.HasOne(x => x.Ride).WithMany()
.HasForeignKey(x => x.RideId)
.HasPrincipalKey(x => x.Id);
});
migrationBuilder.CreateTable(
name: "RidePrices",
columns: table => new
{
FromId = table.Column<Guid>(type: "uuid", nullable: false),
ToId = table.Column<Guid>(type: "uuid", nullable: false),
RideId = table.Column<Guid>(type: "uuid", nullable: false),
Price = table.Column<decimal>(type: "numeric", nullable: false),
RideId1 = table.Column<Guid>(type: "uuid", nullable: true)
},
table.ForeignKey(
name: "FK_RidePrices_Rides_RideId",
column: x => x.RideId,
principalTable: "Rides",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_RidePrices_Rides_RideId1",
column: x => x.RideId1,
principalTable: "Rides",
principalColumn: "Id");
2
Answers
Oh, how foolish it turned out. I added
x => x.Prices
to theWithMany
operator, and everything started working. I spent about 2 hours trying to do it this way and that. I gave up and posted the question here. The whole day didn't touch this issue, and then I solved it in 3 minutes.RidePrice will need it’s own PK declared, whether an identity column I.e. RidePriceId, or a composite key between RideId, FromId, ToId, etc. Either that or consider whether Rides will actually have multiple prices, or should it be a One-to-One in which case RidePrice can use RideId as the PK and EF will happily join these up as a one-to-one.
You will likely also have an issue with the waypoint columns in the RidePrice. Add FK nominations either via attributes or entity configuration:
The reason is that EF conventions will link FK properties by Type rather than by property name, so since these are both type "Waypoint" it would be looking for, or creating shadow properties for "WaypointId" and "WaypointId_1".