EF Core影子列

huangapple go评论53阅读模式
英文:

EF Core shadow column

问题

EF Core为你的模型“RidePrice”添加“RideId1”属性的原因是因为在实体类型中存在一个与之冲突的简单名称为“RideId”的属性,但该属性要么未映射,要么已用于另一个关系,或者与关联的主键类型不兼容。这是EF检测到的冲突。

即使从“RidePrice”中移除“RideId”和“Ride”属性,EF仍然会添加一个影子属性,只是名称不同。

你可以假设影子属性是从“Waypoint”派生的,但你需要了解如何管理这样的关系。

如果EF添加的属性确实是必要的,你可以将其包含在模型中,但需要明确了解此属性用于哪个关系。

英文:

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"<br/>
Microsoft.EntityFrameworkCore.Tools Version="7.0.5"<br/>
Npgsql.EntityFrameworkCore.PostgreSQL Version="7.0.4"

public class Ride
{
	public Guid Id { get; set; }
	public IReadOnlyList&lt;Waypoint&gt; Waypoints { get; set; }
	public IReadOnlyList&lt;RidePrice&gt; 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&lt;Ride&gt;(entityBuilder =&gt;
{
	entityBuilder.HasMany(x =&gt; x.Prices).WithOne(x =&gt; x.Ride)
        .HasForeignKey(x =&gt; x.RideId)
        .HasPrincipalKey(x =&gt; x.Id);

	entityBuilder.HasMany(x =&gt; x.Waypoints).WithOne();
});

modelBuilder.Entity&lt;Waypoint&gt;(entityBuilder =&gt;
{
	entityBuilder.HasOne(x =&gt; x.Ride).WithMany(x =&gt; x.Waypoints);
});

modelBuilder.Entity&lt;RidePrice&gt;(entityBuilder =&gt;
{
	entityBuilder.HasKey(x =&gt; new { x.FromId, x.ToId });

	entityBuilder.HasOne(x =&gt; x.From).WithMany().HasForeignKey(x =&gt; x.FromId);
	entityBuilder.HasIndex(x =&gt; x.FromId);

	entityBuilder.HasOne(x =&gt; x.To).WithMany().HasForeignKey(x =&gt; x.ToId);
	entityBuilder.HasIndex(x =&gt; x.ToId);

	entityBuilder.HasOne(x =&gt; x.Ride).WithMany()
        .HasForeignKey(x =&gt; x.RideId)
        .HasPrincipalKey(x =&gt; x.Id);
});
migrationBuilder.CreateTable(
    name: &quot;RidePrices&quot;,
    columns: table =&gt; new
    {
        FromId = table.Column&lt;Guid&gt;(type: &quot;uuid&quot;, nullable: false),
        ToId = table.Column&lt;Guid&gt;(type: &quot;uuid&quot;, nullable: false),
        RideId = table.Column&lt;Guid&gt;(type: &quot;uuid&quot;, nullable: false),
        Price = table.Column&lt;decimal&gt;(type: &quot;numeric&quot;, nullable: false),
        RideId1 = table.Column&lt;Guid&gt;(type: &quot;uuid&quot;, nullable: true)
    },
    
table.ForeignKey(
    name: &quot;FK_RidePrices_Rides_RideId&quot;,
    column: x =&gt; x.RideId,
    principalTable: &quot;Rides&quot;,
    principalColumn: &quot;Id&quot;,
    onDelete: ReferentialAction.Cascade);
table.ForeignKey(
    name: &quot;FK_RidePrices_Rides_RideId1&quot;,
    column: x =&gt; x.RideId1,
    principalTable: &quot;Rides&quot;,
    principalColumn: &quot;Id&quot;);

答案1

得分: 0

RidePrice需要声明自己的主键,无论是一个标识列,比如RidePriceId,还是一个由RideId、FromId、ToId等组成的复合主键。要么这样,要么考虑一下Rides是否实际上会有多个价格,或者是否应该是一对一的关系,如果是这样的话,RidePrice可以使用RideId作为主键,EF将会愉快地将它们作为一对一连接起来。

你可能还会遇到RidePrice中的waypoint列的问题。通过属性或实体配置添加外键引用:

[ForeignKey(nameof(From))]
public Guid FromId { get; set; }
public Waypoint From { get; set; }

[ForeignKey(nameof(To))]
public Guid ToId { get; set; }
public Waypoint To { get; set; }

原因是EF约定将根据类型而不是属性名称来链接FK属性,因此由于它们都是类型“Waypoint”,它将查找或创建"WaypointId"和"WaypointId_1"的影子属性。

英文:

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:

[ForeignKey(nameof(From))]
public Guid FromId { get; set; }
public Waypoint From { get; set; }

[ForeignKey(nameof(To))]
public Guid ToId { get; set; }
public Waypoint To { get; set; }

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".

答案2

得分: 0

Oh, how foolish it turned out. I added x => x.Prices to the WithMany 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.

英文:

Oh, how foolish it turned out. I added x =&gt; x.Prices to the WithMany 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.

huangapple
  • 本文由 发表于 2023年5月22日 04:11:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76301743.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定