使用 Entity Framework Core 添加具有现有导航属性的元素

问题描述 投票:0回答:1
 public async Task<bool> CreateAsync(CreateSampleDto createSampleDto)
 {
     Sample sample = new()
     {
         YarnName = createSampleDto.YarnName,
         LoopsQuantity = createSampleDto.LoopsQuantity,
         RowsQuantity = createSampleDto.RowsQuantity,
         NeedleSize = createSampleDto.NeedleSize,
         NeedleSizeUnit = createSampleDto.NeedleSizeUnit,
         Description = createSampleDto.Description,
         User = _userService.GetUserByIdAsync(createSampleDto.UserId)
     };

     await _databaseContext.Samples.AddAsync(sample);
     await _databaseContext.SaveChangesAsync();
     return true;
 }

我想使用实体框架将新的 Sample 对象添加到数据库中。示例具有名为“用户”的导航属性(用户有许多示例)。我想在代码中仅使用导航属性,但我认为使用这种方法从数据库获取用户可能效率低下。当我创建新的 Sample 对象时,是否有更好的方法来附加数据库中存在的用户?我尝试使用 Attach() 函数,但我根本无法处理它。

c# entity-framework entity-framework-core
1个回答
0
投票

这个方法非常标准。通过 ID 获取用户应该是一个相对快速的操作,它还可以验证用户是否存在,并且可以强制执行任何较低级别的规则。例如,如果您正在构建一个多租户 SAAS 系统,其中来自不同租户的不同用户位于同一数据库中,您的服务将具有代码来确保为当前登录会话检索的数据仅相关,即获取其注册的租户 ID。如果您的代码仅设置 FK,则可能存在将无效 FK 分配给记录的风险。 (即存在的记录的 FK,但不应应用于此用户/场景)

如果不存在分配不正确 FK 的潜在问题,另一种方法是将存根附加到 DbContext 来表示现有记录。但是,特别是在使用注入的 DbContext 和可能属于较大工作链的操作时,您应始终在附加实体之前检查 DbContext 跟踪缓存。如果不这样做,可能会导致上下文已经在跟踪匹配实体的情况异常。

bool usedStub = false;
var user = _context.Users.Local
    .FirstOrDefault(x => x.UserId == createSampleDto.UserId);
if (user == null)
{
    user = new User { UserId = createSampleDto.UserId };
    _context.Attach(user);
    usedStub = true;
}

 Sample sample = new()
 {
     YarnName = createSampleDto.YarnName,
     LoopsQuantity = createSampleDto.LoopsQuantity,
     RowsQuantity = createSampleDto.RowsQuantity,
     NeedleSize = createSampleDto.NeedleSize,
     NeedleSizeUnit = createSampleDto.NeedleSizeUnit,
     Description = createSampleDto.Description,
     User = user
 };

_context.Samples.Add(sample);
await _context.SaveChangesAsync();

// Remove the stub
if (usedStub)
    _context.Entry(user).State = EntityState.Detached;

前提是检查用户的本地跟踪缓存,如果找到,我们将使用它。此检查不会进入数据库。如果尚未跟踪它,那么我们可以创建存根并附加它。由于我们附加了一个仅包含 UserID 的存根,因此我们不希望 DbContext 在稍后可能希望在请求中加载实际用户的情况下返回该存根,因此如果我们添加了一个存根,那么我们会分离该存根一次我们完成了。

现在将其应用到现有的 UserService 模式中可能不会那么简单。这是抽象 DbContext 可能出现问题的原因之一,因此像您当前所做的那样使用 UserService 加载用户可能更安全。

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