fix: 统一逐租户上下文执行
This commit is contained in:
@@ -16,7 +16,6 @@ public sealed class DictionaryGroupRepository(DictionaryDbContext context) : IDi
|
||||
EF.CompileAsyncQuery((DictionaryDbContext db, long tenantId, DictionaryCode code) =>
|
||||
db.DictionaryGroups
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.FirstOrDefault(group => group.TenantId == tenantId && group.DeletedAt == null && group.Code == code));
|
||||
|
||||
/// <summary>
|
||||
@@ -25,7 +24,7 @@ public sealed class DictionaryGroupRepository(DictionaryDbContext context) : IDi
|
||||
public Task<DictionaryGroup?> GetByIdAsync(long groupId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.DictionaryGroups
|
||||
.IgnoreQueryFilters()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(group => group.Id == groupId && group.DeletedAt == null, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -90,7 +89,6 @@ public sealed class DictionaryGroupRepository(DictionaryDbContext context) : IDi
|
||||
|
||||
return await context.DictionaryGroups
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Where(group => ids.Contains(group.Id) && group.DeletedAt == null)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
@@ -144,7 +142,6 @@ public sealed class DictionaryGroupRepository(DictionaryDbContext context) : IDi
|
||||
{
|
||||
var query = context.DictionaryGroups
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Where(group => group.TenantId == tenantId && group.DeletedAt == null);
|
||||
|
||||
if (scope.HasValue)
|
||||
|
||||
@@ -3,19 +3,19 @@ using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Dictionary.Entities;
|
||||
using TakeoutSaaS.Domain.Dictionary.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Dictionary.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 字典项仓储实现。
|
||||
/// </summary>
|
||||
public sealed class DictionaryItemRepository(DictionaryDbContext context) : IDictionaryItemRepository
|
||||
public sealed class DictionaryItemRepository(DictionaryDbContext context, ITenantContextAccessor tenantContextAccessor) : IDictionaryItemRepository
|
||||
{
|
||||
private static readonly Func<DictionaryDbContext, long, long, IEnumerable<DictionaryItem>> GetByGroupQuery =
|
||||
EF.CompileQuery((DictionaryDbContext db, long tenantId, long groupId) =>
|
||||
(IEnumerable<DictionaryItem>)db.DictionaryItems
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Where(item => item.GroupId == groupId && item.TenantId == tenantId && item.DeletedAt == null)
|
||||
.OrderBy(item => item.SortOrder));
|
||||
|
||||
@@ -25,7 +25,7 @@ public sealed class DictionaryItemRepository(DictionaryDbContext context) : IDic
|
||||
public Task<DictionaryItem?> GetByIdAsync(long itemId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.DictionaryItems
|
||||
.IgnoreQueryFilters()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(item => item.Id == itemId && item.DeletedAt == null, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -51,25 +51,26 @@ public sealed class DictionaryItemRepository(DictionaryDbContext context) : IDic
|
||||
bool includeOverrides,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var systemGroup = await context.DictionaryGroups
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.FirstOrDefaultAsync(group => group.Id == systemGroupId && group.DeletedAt == null, cancellationToken);
|
||||
|
||||
if (systemGroup == null)
|
||||
DictionaryGroup? systemGroup;
|
||||
List<DictionaryItem> systemItems;
|
||||
using (tenantContextAccessor.EnterTenantScope(0, "dictionary"))
|
||||
{
|
||||
return Array.Empty<DictionaryItem>();
|
||||
systemGroup = await context.DictionaryGroups
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(group => group.Id == systemGroupId && group.DeletedAt == null, cancellationToken);
|
||||
if (systemGroup == null)
|
||||
{
|
||||
return Array.Empty<DictionaryItem>();
|
||||
}
|
||||
|
||||
systemItems = await context.DictionaryItems
|
||||
.AsNoTracking()
|
||||
.Where(item => item.GroupId == systemGroupId && item.DeletedAt == null)
|
||||
.OrderBy(item => item.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
var result = new List<DictionaryItem>();
|
||||
var systemItems = await context.DictionaryItems
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Where(item => item.GroupId == systemGroupId && item.TenantId == 0 && item.DeletedAt == null)
|
||||
.OrderBy(item => item.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
result.AddRange(systemItems);
|
||||
var result = new List<DictionaryItem>(systemItems);
|
||||
|
||||
if (!includeOverrides || tenantId == 0)
|
||||
{
|
||||
@@ -78,7 +79,6 @@ public sealed class DictionaryItemRepository(DictionaryDbContext context) : IDic
|
||||
|
||||
var tenantGroup = await context.DictionaryGroups
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.FirstOrDefaultAsync(group =>
|
||||
group.TenantId == tenantId &&
|
||||
group.DeletedAt == null &&
|
||||
@@ -92,7 +92,6 @@ public sealed class DictionaryItemRepository(DictionaryDbContext context) : IDic
|
||||
|
||||
var tenantItems = await context.DictionaryItems
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Where(item => item.GroupId == tenantGroup.Id && item.TenantId == tenantId && item.DeletedAt == null)
|
||||
.OrderBy(item => item.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
@@ -17,7 +17,6 @@ public sealed class DictionaryLabelOverrideRepository(DictionaryDbContext contex
|
||||
public Task<DictionaryLabelOverride?> GetByIdAsync(long id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.DictionaryLabelOverrides
|
||||
.IgnoreQueryFilters()
|
||||
.Include(x => x.DictionaryItem)
|
||||
.FirstOrDefaultAsync(x => x.Id == id && x.DeletedAt == null, cancellationToken);
|
||||
}
|
||||
@@ -28,7 +27,6 @@ public sealed class DictionaryLabelOverrideRepository(DictionaryDbContext contex
|
||||
public Task<DictionaryLabelOverride?> GetByItemIdAsync(long tenantId, long dictionaryItemId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.DictionaryLabelOverrides
|
||||
.IgnoreQueryFilters()
|
||||
.FirstOrDefaultAsync(x =>
|
||||
x.TenantId == tenantId &&
|
||||
x.DictionaryItemId == dictionaryItemId &&
|
||||
@@ -46,7 +44,6 @@ public sealed class DictionaryLabelOverrideRepository(DictionaryDbContext contex
|
||||
{
|
||||
var query = context.DictionaryLabelOverrides
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Include(x => x.DictionaryItem)
|
||||
.Where(x => x.TenantId == tenantId && x.DeletedAt == null);
|
||||
|
||||
@@ -71,7 +68,6 @@ public sealed class DictionaryLabelOverrideRepository(DictionaryDbContext contex
|
||||
|
||||
return await context.DictionaryLabelOverrides
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Where(x =>
|
||||
x.TenantId == tenantId &&
|
||||
ids.Contains(x.DictionaryItemId) &&
|
||||
|
||||
@@ -4,13 +4,14 @@ using TakeoutSaaS.Domain.Dictionary.Enums;
|
||||
using TakeoutSaaS.Domain.Dictionary.ValueObjects;
|
||||
using TakeoutSaaS.Domain.Dictionary.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Dictionary.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// EF Core 字典仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfDictionaryRepository(DictionaryDbContext context) : IDictionaryRepository
|
||||
public sealed class EfDictionaryRepository(DictionaryDbContext context, ITenantContextAccessor tenantContextAccessor) : IDictionaryRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据分组 ID 查询分组。
|
||||
@@ -163,19 +164,37 @@ public sealed class EfDictionaryRepository(DictionaryDbContext context) : IDicti
|
||||
return Array.Empty<DictionaryItem>();
|
||||
}
|
||||
|
||||
// 2. 构建查询并忽略 QueryFilter
|
||||
var query = context.DictionaryItems
|
||||
// 2. 查询当前租户条目
|
||||
var tenantItems = await context.DictionaryItems
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Include(item => item.Group)
|
||||
.Where(item => normalizedCodes.Contains(item.Group!.Code) && item.DeletedAt == null);
|
||||
|
||||
// 3. 按租户或系统级过滤
|
||||
query = query.Where(item => item.TenantId == tenantId || (includeSystem && item.TenantId == 0));
|
||||
|
||||
// 4. 排序返回
|
||||
return await query
|
||||
.Where(item => item.TenantId == tenantId && normalizedCodes.Contains(item.Group!.Code) && item.DeletedAt == null)
|
||||
.OrderBy(item => item.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (!includeSystem)
|
||||
{
|
||||
return tenantItems;
|
||||
}
|
||||
|
||||
// 3. (空行后) 查询系统级条目(TenantId=0)
|
||||
List<DictionaryItem> systemItems;
|
||||
using (tenantContextAccessor.EnterTenantScope(0, "dictionary"))
|
||||
{
|
||||
systemItems = await context.DictionaryItems
|
||||
.AsNoTracking()
|
||||
.Include(item => item.Group)
|
||||
.Where(item => item.TenantId == 0 && normalizedCodes.Contains(item.Group!.Code) && item.DeletedAt == null)
|
||||
.OrderBy(item => item.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
// 4. (空行后) 合并返回(系统优先)
|
||||
if (systemItems.Count == 0)
|
||||
{
|
||||
return tenantItems;
|
||||
}
|
||||
|
||||
return [.. systemItems, .. tenantItems];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ public sealed class TenantDictionaryOverrideRepository(DictionaryDbContext conte
|
||||
public Task<TenantDictionaryOverride?> GetAsync(long tenantId, long systemGroupId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.TenantDictionaryOverrides
|
||||
.IgnoreQueryFilters()
|
||||
.FirstOrDefaultAsync(config =>
|
||||
config.TenantId == tenantId &&
|
||||
config.SystemDictionaryGroupId == systemGroupId &&
|
||||
@@ -31,7 +30,6 @@ public sealed class TenantDictionaryOverrideRepository(DictionaryDbContext conte
|
||||
{
|
||||
return await context.TenantDictionaryOverrides
|
||||
.AsNoTracking()
|
||||
.IgnoreQueryFilters()
|
||||
.Where(config => config.TenantId == tenantId && config.DeletedAt == null)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user