如何从EF Core建立的一对一关系中获取相关数据?

How to get related data from one to one relationship built by EF Core?

我有模型 class 继承自 IdentityUser,它具有一对一的关系

public class CustomUser: IdentityUser
{
    public ExtendedUserData ExtendedData { get; set; }
}

我有一个 ExtendedData 模型 class:

public class ExtendedUserData
{
    public Guid Id { get; set; }

    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string Contract { get; set; }
    public string ExtendedDataOfCustomUserId { get; set; }
    public CustomUser CustomUser { get; set; }
}

(用 this EF core tutorial 制作)

但是,如果我使用这种方法获取数据

public ExtendedUserData GetExtendedUserDataById(Guid id)
{
    return context.ExtendedUserDatas
                  .FirstOrDefault(x => x.ExtendedDataOfCustomUserId == id.ToString());
}

我试着这样制作

ExtendedUserData userData = new ExtendedUserData();
userData = GetExtendedUserDataById(id);
....
userData.CustomUser.Id;

userData.CustomUser.UserName;

我收到一个错误。像 NullRefExc

如何使用 1 对 1 关系从 ExtendedUserData(或 mb CustomUser)获取相关数据?

我想到了这个,但除此之外我没有想出任何其他的

public ExtendedUserData GetExtendedUserDataById(Guid id)
{
    ExtendedUserData ud = context.ExtendedUserDatas
                                 .FirstOrDefault(x => x.ExtendedDataOfCustomUserId == id.ToString());
    ud.CustomUser = context.CustomUsers
                           .FirstOrDefault(x => x.Id == id.ToString());
    return ud;
}

也许这可以做得更正确或更短?

感谢您的回答!

如果您已经加载了 CustomUser 并由 EF 跟踪,这应该可行。如果你只有身份证,你必须自己处理相关数据。几种方式:

使用预先加载

public ExtendedUserData GetExtendedUserDataById(Guid id)
{
    return context.ExtendedUserDatas
                  .Include(x => x.CustomUser)
                  .FirstOrDefault(x => x.ExtendedDataOfCustomUserId == id.ToString())
                  ;
}

当您知道每个消费者都希望加载 CustomUser 时很好。在一般的代码中,很难说出你需要提前包含什么(CustomUser 也可以有你可能想要加载的相关实体等等,导致 .Include(...).ThenInclude(...) 的长链)。

使用显式加载

public ExtendedUserData GetExtendedUserDataById(Guid id)
{
    var user = context.ExtendedUserDatas
                  .FirstOrDefault(x => x.ExtendedDataOfCustomUserId == id.ToString())
                   ;
    if (user != null)
    {
        context.Entry(user).Reference(x => x.CustomUser).Load();
    }
    return user;
}

这并没有像写的那样有意义。但是由于任何人都可以做到这一点,因此您可以将加载相关数据的责任传递给更了解其需求的消费者。当关系链变长并包含集合时,写起来有点痛苦。

还有延迟加载隐藏了所有这些复杂性,但您必须采取一些步骤来激活它,如果您忘记了它的存在,它很容易扼杀您的性能。关于这三个的更多信息:https://docs.microsoft.com/en-us/ef/core/querying/related-data#lazy-loading