EF Core - 即使更改跟踪器已加载其条目,拥有的类型仍为空

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

我正在尝试配置一个具有可为空值对象

User
的聚合根
ChangePasswordCode
。当我在存储库中调用
_dbContext.Users.FirstOrDefaultAsync
时,即使数据存在于数据库中,我也会收到一个带有 null
User
ChangePasswordCode
对象。

代码如下:

public class User : AggregateRoot<UserId>
{
    private readonly List<Ban> _bans = [];

    public Name Name { get; private set; }

    public Email Email { get; private set; }

    public Password Password { get; private set; }

    public DepartmentId DepartmentId { get; private set; }

    public Roles Roles { get; private set; }

    public IReadOnlyList<Ban> Bans => _bans.AsReadOnly();

    public ChangePasswordCode? ChangePasswordCode { get; private set; }

#pragma warning disable CS8618
    private User() { }
#pragma warning restore CS8618

    private User(
        UserId id,
        Name name,
        Email email,
        Password password,
        DepartmentId departmentId,
        Roles roles) : base(id)
    {
        Name = name;
        Email = email;
        Password = password;
        DepartmentId = departmentId;
        Roles = roles;
    }
    ...
}
public class ChangePasswordCode : ValueObject
{
    public string Value { get; private set; }

    public DateTime ExpiryTime { get; private set; }

    public ChangePasswordCode(string value, DateTime expiryTime)
    {
        Value = value;
        ExpiryTime = expiryTime;
    }
    ...
}
internal class UserConfigurations : IEntityTypeConfiguration<User>
{
    ...
    private void ConfigureUsersTable(EntityTypeBuilder<User> builder)
    {
        ...

        builder.OwnsOne(u => u.ChangePasswordCode);
        ...

这是 DbContextSnapshop:

b.OwnsOne("Domain.UserAggregate.ValueObjects.ChangePasswordCode", "ChangePasswordCode", b1 =>
    {
        b1.Property<Guid>("UserId")
            .HasColumnType("uuid");

        b1.Property<DateTime>("ExpiryTime")
            .HasColumnType("timestamp with time zone");

        b1.Property<string>("Value")
            .IsRequired()
            .HasColumnType("text");

        b1.HasKey("UserId");

        b1.ToTable("Users");

        b1.WithOwner()
            .HasForeignKey("UserId");
    });

b.Navigation("ChangePasswordCode");

这是问题发生的地方:

internal class UserRepository : IUserRepository
{
    private readonly IdearDbContext _context;

    public UserRepository(IdearDbContext context)
    {
        _context = context;
    }

    public async Task<User?> GetByIdAsync(UserId id, CancellationToken cancellationToken = default)
    {
        var user = await _context.Users
            .FirstOrDefaultAsync(u => u.Id == id, cancellationToken);

        return user; // user.ChangePasswordCode is null here
    }

我尝试检查更改跟踪器调试视图以查看数据是否实际正确检索,并且调试视图是:

User {Id: Domain.UserAggregate.ValueObjects.UserId} Unchanged
    Id: 'Domain.UserAggregate.ValueObjects.UserId' PK
    DepartmentId: 'Domain.DepartmentAggregate.ValueObjects.DepartmentId' FK
    Email: 'Domain.UserAggregate.ValueObjects.Email'
    Name: 'Domain.Shared.ValueObjects.Name'
    Password: 'Domain.UserAggregate.ValueObjects.Password'
    Roles: 'Admin'
  Bans: []
  ChangePasswordCode: <null>
ChangePasswordCode {UserId: Domain.UserAggregate.ValueObjects.UserId} Unchanged
    UserId: 'Domain.UserAggregate.ValueObjects.UserId' PK FK
    ExpiryTime: '11/20/2024 9:31:31 AM'
    Value: 'B20BB3'

奇怪的是,ChangePasswordCode 实际上已加载并跟踪,但由于某种原因,它没有附加到

User
条目。

我发现了一个类似的问题here,并尝试了该建议,但它仍然为空。我还尝试切换到不可为空的

ChangePasswordCode
属性,它确实使该字段在数据库中成为必需的,但当映射到
User
对象时它仍然为空。

c# postgresql entity-framework-core ef-core-8.0 owned-types
1个回答
0
投票

TL;DR - 我对

GetHashCode
实施了错误的
ValueObject
方法。

创建一个不同的项目来测试

User
ChangePasswordCode
后,我发现问题出在
UserId
值对象上,因为当我使用
Guid
作为主键时它工作正常。当时,我怀疑更改跟踪器可能会比较
UserId
User
条目中的 2 个
ChangePasswordCode
,但不知何故与 2 不匹配。所以问题可能出在
Equals
GetHashCode
方法中我为
ValueObject
实施。

通过在调试模式下放置断点,我发现更改跟踪器确实在

GetHashCode
之前先调用
Equals
,并且它为相同的
UserId
返回 2 个不同的哈希代码。我修复了
GetHashCode
方法,现在它可以工作了。

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