如何在 Entity Framework Core 8.0.8 中更新父类和 [Owned] 属性类类型的数据库

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

如何将父类的

[Owned]
属性类数据保存到数据库中。

这是父类:

[Index(nameof(EmailId),IsUnique =true)]
public class User : Entity, IUser
{
   [Required(ErrorMessage ="First Name is required."), MaxLength(20),MinLength(1)]
   [DisplayName("First Name")]
   public string FirstName { get; set; } = string.Empty;

   [DisplayName("Last Name")]
   [Required(ErrorMessage ="Last Name is required."), MaxLength(20),MinLength(1)]
   public string LastName { get; set; } = string.Empty;

   [DisplayName("Email Address")]
   [Required(ErrorMessage = "Email Id is required"), MaxLength(50), MinLength(5)]
   [DataType(DataType.EmailAddress)]
   public string EmailId { get; set; } = string.Empty;

   [JsonIgnore]
   [DisplayName("Password"),MaxLength(200), MinLength(8),DataType(DataType.Password)]
   public string? Password { get; set; }    

   [JsonIgnore]
   public List<RefreshToken> RefreshTokens { get; set; }
}

这是子类

RefreshToken
结构

[Owned]
public class RefreshToken
{
   [Key]
   [JsonIgnore]
   public Guid Id { get; set; }= Guid.NewGuid();
   public string Token { get; set; }
   public DateTime Expires { get; set; }
   public DateTime Created { get; set; }
   public string CreatedByIp { get; set; }
   public DateTime? Revoked { get; set; }
   public string RevokedByIp { get;set; }
   public string ReplacedByToken { get; set; }
   public string ReasonRevoked { get; set; }
   public Boolean IsExpired => DateTime.UtcNow >= Expires;
   public bool IsRevoked => Revoked != null;
   public bool IsActive => !IsRevoked && !IsExpired;
}

这是代码 - 我正在尝试使用刷新令牌值保存父级:

_unitOfWork.BeginTransaction();

User? _user = GetByEmailId(model.EmailId).FirstOrDefault();

// return null if user not found
if (_user == null) 
    throw new AppException("Username or password is incorrect");

if (_user.Password != model.Password.Hash())
    throw new AppException("Username or password is incorrect");

// authentication successful so generate jwt token
var token = _jwtUtils.GenerateJwtToken(_user);
var _refreshtoken = _jwtUtils.GenerateRefreshToken(ipAddress);

_user.RefreshTokens.Add(_refreshtoken);

// remove old refresh token
removeOldRefreshTokens(_user);

apiResponse = _unitOfWork.Repository<User>().Update(_user);
_unitOfWork.SaveChange();
_unitOfWork.CommitTransaction();

保存时出现错误:

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException:数据库操作预计影响 1 行,但实际影响 0 行;

刷新令牌已添加到用户表集合中,但在保存用户表时出现错误

在此输入图片描述

c# authentication entity-framework-core repository-pattern unit-of-work
1个回答
0
投票

看起来大部分都还好,但这可能取决于

removeOldRefreshTokens(_user);
的作用以及
_unitOfWork.Repository<User>().Update(_user);
的作用。

我看到的第一个问题是令牌密钥的客户端生成。这很好,但是当遵循“Id”或“TokenId”约定时,默认情况下 EF 将期望将该键视为 Identity 列。 (由数据库生成)。将其标记为

[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
可能会解决您的问题。

当涉及到“removeOldRefreshTokens”时,只要此方法迭代令牌列表并使用

.Remove()
删除无效项目,那么这应该没问题。我看到的警告标志是如何在用户实体中定义令牌的:

public List<RefreshToken> RefreshTokens { get; set; }

将其更改为:

public virtual ICollection<RefreshToken> RefreshTokens { get; } = [];

没有公共设置者。如果有任何代码对此表示反对,请清理此代码。实体中的导航集合永远不应重新初始化。这将破坏跟踪代理并导致错误。

最后是Update方法。就 EF 而言,通用存储库是一种反模式,并且可能会导致更多问题。 EF 已经提供了一个工作单元作为

DbContext
,并在
DbSet
中提供了一个存储库。任何超出此范围的事情都可能隐藏更改跟踪和引用方面令人烦恼的问题。如果此 Update 方法执行
_context.SaveChanges();
以外的任何操作,那么它很可能会导致问题。如果它调用
DbSet<User>.Update()
,几乎肯定会引起问题。
Update()
适用于分离实体,与跟踪实体相比,使用分离对象图(关系)总是很痛苦。

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