【问题标题】:Entity Framework Core - manually assigning id's to linked entitiesEntity Framework Core - 手动将 id 分配给链接的实体
【发布时间】:2019-01-29 14:10:12
【问题描述】:

我在 StackOverflow 上查看了其他相关问题,但没有找到与我的确切问题或场景匹配的问题。

我有一个 JavaScript 前端,其中有两个链接的实体,所以在前端我有 JSON 对象,它们可以像这样相互“链接”:


实体1

name = "某事"

entity2Id = 0

实体2

第一条记录

id = 0

name = "别的东西"

第二条记录

id = 1

name = "又是别的东西"


然后我将 JSON 发送到 .NET 后端,我的想法是,当我手动指定 entity2 的主键并将其设置为我的 entity1 中的“外键”引用时,Entity Framework 不知何故需要为 entity2 生成有效 id,并在 entity1 的 entity2id 属性中维护对该 id 的引用。

我怀疑我可能把这一切都搞错了,并且有一个相当标准的方法来实现我想要做的事情。我应该怎么做才能达到预期的效果? (我使用的是 SQLite 数据库,这可能没什么区别。)

【问题讨论】:

  • 实际上PK值必须是CLR默认值(0)才能自动生成。因此,您不能通过 entity2Id 将新 entity2 与 entity1 相关联 - entity1 必须包含对 entity2 的引用。
  • 奇怪的是,人们将引用称为“孩子”,而通常它代表“父母”。无论如何,您可能应该提供更多上下文,例如示例类、服务方法的签名等。但基本上 EFC 需要对象,所以 entity1 应该有 entity2 引用,或者 entity2 应该有 entity1 的集合。毕竟,这就是 EF 通过导航属性对关系建模的方式。
  • 啊,不是真的 - Entity1 可以只有一个指向现有 Entity2 的外键,而 ef 会找出其余的。您不需要在 Entity1 上填充整个 Entity2。无论如何,这是推荐的方法。不过不太确定 OP 想要什么。
  • 所以@ChrisHalcrow 你想要:保存 Entity1 时还创建一个新的 Entity2,或者:保存 Entity1 时你只想分配一个现有的 Entity2 给它?如果是后者,那么问题是 Id = 0。EF 会认为它是一个新实体,它不会工作。尝试分配给 Entity2 id = 1,它应该像 Ivan 在他的评论中所说的那样工作。
  • 当然,你肯定可以这样做。两种情况都支持..我会尽快写一些东西:)

标签: sql .net database entity-framework-core


【解决方案1】:

你在那里有一个one-to-many 关系。为了更容易解释,我将您的 Entit1 更改为 Book 并将 Entity2 更改为 Genre。所以是这样的:

public class Book
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int GenreId { get; set; }
    public Genre Genre { get; set; }
}

public class Genre
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Book> Books { get; set; }
}

然后您可以使用 FluentApi 配置关系(最重要的是 Books 上的 FK 键来自 Genres

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Book>()
        .HasOne(p => p.Genre)
        .WithMany(b => b.Books)
        .HasForeignKey(p => p.GenreId);
}

现在我们可以实现你的两个场景:

1 - 创建一个新的Book 以及一个新的Genre

2 - 创建一个新的Book,它使用数据库上现有的Genre

var bookWithNewGenre = new Book
{
    Name = "Book 1",

    // Here we are creating a new Genre, without Id.
    // GenreId here will have the default value of 0, 
    // which EF will use to find out that it has to be created
    Genre = new Genre { Name = "Mistery"}   
};

var bookWithExistingFictionGenre = new Book
{
    Name = "Book 2",

    // Here we are specifying the GenreId = 1 which already exists in the Database
    GenreId = 1,

    // You don't need to set this to null
    // but I like doing it to make EF and my code clear that I'm using an existing Genre
    Genre = null
};

using (var context = new BookContext())
{
    context.Books.Add(bookWithNewGenre);
    context.Books.Add(bookWithExistingFictionGenre);
    await context.SaveChangesAsync();
}

保存后你会在数据库中拥有这个:

您可能必须更改前端才能开始发送Genre 对象。如果是新的,Id 将丢失。当您将其序列化为您的 c# 类型时,您可以确定是否必须创建新实例,或者只是检查传递的 Id 前端是否存在。

备注:我使用Sqlite 和EF 核心包版本2.2.0-preview1-35029 完成了所有这些工作。

【讨论】:

    猜你喜欢
    • 2019-07-31
    • 2016-06-19
    • 2023-03-29
    • 2018-06-09
    • 2022-01-19
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    相关资源
    最近更新 更多