如何在 ASP.NET 中使用实体框架正确执行一对多映射

问题描述 投票:0回答:1

目前我正在使用 ASP.NET 和实体框架。我最近在 Youtube 上浏览了这个教程:https://www.youtube.com/watch?v=aE5Ksj3fris&list=RDCMUC_H7wrnwGU3g1xrLasMf6Gg&start_radio=1&t=632s 现在我正在尝试设置与笔记具有一对多关系的用户(一个用户,多个笔记)。

我相信两个类上用于设置关系的字段都是正确的,但是当我尝试在注释上设置用户时,我被 swagger 告知注释的用户字段不能为空。这样,向用户添加注释就不起作用了。我对此很陌生,因此非常感谢您的帮助,谢谢。

The addNote method I am referring to

The note class

The User class

我尝试让 Note 类中的用户字段可以为空,这样我至少可以向用户添加注释。我希望列表中有一个注释,但它只是创建了注释,并没有添加到注释列表中。为了导航目的,我多次弄乱了这两个类的字段,但这没有做任何事情。

entity-framework asp.net-web-api
1个回答
0
投票

C# 的可为空警告对于实体框架来说可能有点麻烦,并且 EF 通常负责确保引用已初始化并存在。当涉及到集合导航属性时,您应该始终将它们初始化为新的

List
HashSet
,以便它们在构造新实例时准备好接收数据。所以对于用户来说。注意事项:

public virtual ICollection<Note> Notes { get; protected set; } = new List<Note>();

...而不是使用可为空的列表来让编译器满意。请注意,设置器受到保护。实体集合永远不应该重新设置为新集合,因为这会弄乱 EF 的更改跟踪器。这确保了收藏品随时可以使用。对于诸如 Note.User 之类的单一导航属性,请not初始化它们。如果导航属性在数据库中不可为空,则也不要在实体中将其声明为可为空,而是将其添加到公共构造函数中。 (见下文)

向父级添加子级有两种方法:

var user = context.Users
    .Single(u => u.Id == userId);
var note = new Note(user, /* add any/all required fields */);

// Option 1:

user.Notes.Add(note);

// or Option 2:

// context.Notes.Add(note);

context.SaveChanges();

选项 1 可用于 Notes 不需要在

DbSet
上公开
DbContext
并且只能通过其 User.Notes 集合访问的情况。

作为 EF 实体的一般规则,应该有一个公共构造函数来接受所有必需的值和导航属性(不可为 null),然后您可以为 EF 设置一个受保护的默认构造函数,以便在它运行时在幕后使用从数据库加载实体。例如,如果注释需要用户和消息文本属性才有效:

public Note(User user, string message)
{
    ArgumentNullException.ThrowIfNull(user, nameof(user));
    ArgumentException.ThrowIfNullOrEmpty(message, nameof(message));

    User = user;
    Message = message;
}

 #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
    /// <summary>
    /// Constructor used by EF.
    /// </summary>
    [ExcludeFromCodeCoverage]
    protected Note()
    { }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.

这让编译器“高兴”。实体中的任何可选内容都可以为空,其中所需的任何内容都应通过构造函数添加。

在初始化关系时,您可以使用导航属性 (Note.User) 或 FK 属性。 (Note.UserId) 如果同时设置两者,则导航属性优先。通常我建议使用其中之一,而不是同时使用两者。例如,当使用导航属性时,使用 FK 的阴影属性。 (没有 Note.UserId 作为属性公开)通过设置导航属性,它确实会产生往返数据库的成本,但无论如何您通常都需要来自实体的信息,并且如果提取数据时出现问题,则异常会发生在读取数据的点而不是

SaveChanges
。对于性能至关重要的情况,或者处理诸如值不改变的查找表之类的事情,使用 FK 更好。

© www.soinside.com 2019 - 2024. All rights reserved.