Entity Framework Core - 外键1(额外的外键列)

8

我刚刚升级到了Entity Framework Core 2,现在出现了问题,即使它不在我的模型中且没有在任何其他地方定义,但仍存在一个额外的列并具有唯一键。

索引:

migrationBuilder.CreateTable(
    name: "Vouchers",
    columns: table => new
    {
        Id = table.Column<int>(nullable: false)
            .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
        Code = table.Column<Guid>(nullable: false),
        IsClaimed = table.Column<bool>(nullable: false),
        LastModified = table.Column<DateTime>(nullable: false),
        NumberOfUnits = table.Column<int>(nullable: false),
        TransactionId = table.Column<int>(nullable: false),
        TransactionId1 = table.Column<int>(nullable: true) // why is this here?
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_Vouchers", x => x.Id);
        table.ForeignKey(
            name: "FK_Vouchers_Transactions_TransactionId1",
            column: x => x.TransactionId1,
            principalTable: "Transactions",
            principalColumn: "Id",
            onDelete: ReferentialAction.Restrict);
    });

模型中不存在 TransactionId1:

public class Voucher : IAutoLastModified
{
    public int Id { get; set; }
    public DateTime LastModified { get; set; }

    public int TransactionId { get; set; }
    public Transaction Transaction { get; set; }

    public int NumberOfUnits { get; set; }
    public Guid Code { get; set; }
    public bool IsClaimed { get; set; }
}

我定义外键的方式是否有误?
modelBuilder.Entity<Voucher>().HasOne(x => x.Transaction).WithOne(x => x.Voucher).IsRequired(false);

我的应用程序失败了,因为TransactionId1始终为空,并且具有我无法删除的唯一约束。
为什么EF会为这个表创建一个额外的列?
6个回答

11

如果您将模型定义为双向绑定但在流畅中忘记使用它,可能也会发生这种情况:

public class Customer
{
    public Guid Id { get; set; }
    public List<Order> Orders {get; set;}
}

public class Order
{
    public Guid Id { get; set; }
    
    public Guid CustomerId { get; set; }
    public Guid Customer { get; set; }
}

// AppDbContext
builder.Entity<Order>()
     .HasOne(x => x.Customer) // <-- EDIT: Also use it like this, not .HasOne<Customer>()
     .WithMany() //WRONG -> should be .WithMany(x => x.Orders) OR modify the model to not define the collection at the customer entity
     .HasForeignKey(x => x.CustomerId)
     .OnDelete(DeleteBehavior.SetNull)
;

1
谢谢!我花了差不多一天的时间,如果没有这个帮助,我可能还要花更多的时间。 - yibe

6

好的,我弄清楚了问题所在(将这个问题留在这里是为了帮助其他犯同样错误的人)。

我将关系标记为可选的,但列是int而不是int?,因此EF决定在幕后添加自己的列。

修复后,我不得不重新创建数据库——迁移由于现有数据未能成功完成。


1
当子表中的外键字段类型与父表中的主键字段类型不匹配时,我遇到了这个问题。
示例:
public class User // Parent
{
    public long Id { get; set; }
    public virtual ICollection<UserLike> UserLikes { get; set; } // Child collection
}

public class UserLike // Child
{
    public int Id { get; set; }
    public int UserId { get; set; } // Foreign key
    public virtual User User { get; set; } // Navigation property
}

DbContext中,我有:
modelBuilder.Entity<UserLike>(entity =>
{
    entity.HasOne(x => x.User)
    .WithMany(x => x.UserLikes)
    .OnDelete(DeleteBehavior.ClientCascade);
}

在这里,int UserId与父项中的主键类型long Id不匹配。解决方案是将UserId改为long
public class UserLike // Child
{
    public int Id { get; set; }
    public long UserId { get; set; } // Foreign key
    public virtual User User { get; set; } // Navigation property
}

0

我曾经遇到过同样的问题,解决方法是在导航属性上方添加DataAnnotation标签[ForeignKey("")],明确指定要使用哪一个。

public Guid TransactionId { get; set; }

[ForeignKey("TransactionId ")]
public Transaction Transaction { get; set; }

谢谢


0

您需要告诉模型构建器,您想要将哪个列作为外键列在您的voucher表中使用。否则,实体框架将会自动为您创建一个。

为此,请在流畅设置中添加一个HasForeignKey方法:

modelBuilder.Entity<Voucher>().HasOne(x => x.Transaction).WithOne(x => x.Voucher).HasForeignKey<Voucher>(x => x.TransactionId).IsRequired(false);

在设置一对一关系时,需要将外键存在的实体定义为通用约束。


0

我曾经在使用数据优先方法时遇到过这个问题。我不得不删除一个现有的列,但是每次更新后,该列都会出现在edmx模式结构中,我不得不手动删除才能使其正常工作。你能否重新创建edmx而不是更新它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接