feat: 😀优化字典模块

1. 根据`SysFlag`字段区分平台字典与业务字典
2. 平台字典仅对超管用户可见
3. 字典值支持租户隔离
4. 前端获取的字典集 = 平台字典 + 业务字典
This commit is contained in:
喵你个旺呀 2025-01-15 18:09:35 +08:00
parent 25ab7ac88f
commit 7a796ddeac
6 changed files with 70 additions and 30 deletions

View File

@ -12,7 +12,7 @@ namespace Admin.NET.Core;
[SugarTable(null, "系统字典值表")] [SugarTable(null, "系统字典值表")]
[SysTable] [SysTable]
[SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)] [SugarIndex("index_{table}_C", nameof(Code), OrderByType.Asc)]
public partial class SysDictData : EntityBase public partial class SysDictData : EntityTenant
{ {
/// <summary> /// <summary>
/// 字典类型Id /// 字典类型Id

View File

@ -343,6 +343,24 @@ public enum ErrorCodeEnum
[ErrorCodeItemMetadata("禁止修改枚举类型的字典编码")] [ErrorCodeItemMetadata("禁止修改枚举类型的字典编码")]
D3007, D3007,
/// <summary>
/// 禁止增加系统内置字典
/// </summary>
[ErrorCodeItemMetadata("禁止增加系统内置字典")]
D3008,
/// <summary>
/// 禁止修改系统内置字典
/// </summary>
[ErrorCodeItemMetadata("禁止修改系统内置字典")]
D3009,
/// <summary>
/// 禁止删除系统内置字典
/// </summary>
[ErrorCodeItemMetadata("禁止删除系统内置字典")]
D3010,
/// <summary> /// <summary>
/// 菜单已存在 /// 菜单已存在
/// </summary> /// </summary>

View File

@ -117,7 +117,8 @@ public class EnumToDictJob : IJob
Code = u.TypeName, Code = u.TypeName,
Name = u.TypeDescribe, Name = u.TypeDescribe,
Remark = u.TypeRemark, Remark = u.TypeRemark,
Status = StatusEnum.Enable Status = StatusEnum.Enable,
SysFlag = YesNoEnum.Y,
}).ToList(); }).ToList();
// 新增字典数据 // 新增字典数据

View File

@ -19,13 +19,13 @@ public class SysDictTypeSeedData : ISqlSugarEntitySeedData<SysDictType>
{ {
return return
[ [
new SysDictType{ Id=1300000000101, Name="代码生成控件类型", Code="code_gen_effect_type", OrderNo=100, Remark="代码生成控件类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysDictType{ Id=1300000000101, Name="代码生成控件类型", Code="code_gen_effect_type", SysFlag=YesNoEnum.Y, OrderNo=100, Remark="代码生成控件类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysDictType{ Id=1300000000102, Name="代码生成查询类型", Code="code_gen_query_type", OrderNo=101, Remark="代码生成查询类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysDictType{ Id=1300000000102, Name="代码生成查询类型", Code="code_gen_query_type", SysFlag=YesNoEnum.Y, OrderNo=101, Remark="代码生成查询类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysDictType{ Id=1300000000103, Name="代码生成.NET类型", Code="code_gen_net_type", OrderNo=102, Remark="代码生成.NET类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysDictType{ Id=1300000000103, Name="代码生成.NET类型", Code="code_gen_net_type", SysFlag=YesNoEnum.Y, OrderNo=102, Remark="代码生成.NET类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysDictType{ Id=1300000000104, Name="代码生成方式", Code="code_gen_create_type", OrderNo=103, Remark="代码生成方式", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysDictType{ Id=1300000000104, Name="代码生成方式", Code="code_gen_create_type", SysFlag=YesNoEnum.Y, OrderNo=103, Remark="代码生成方式", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysDictType{ Id=1300000000105, Name="代码生成基类", Code="code_gen_base_class", OrderNo=104, Remark="代码生成基类", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") }, new SysDictType{ Id=1300000000105, Name="代码生成基类", Code="code_gen_base_class", SysFlag=YesNoEnum.Y, OrderNo=104, Remark="代码生成基类", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysDictType{ Id=1300000000106, Name="代码生成打印类型", Code="code_gen_print_type", OrderNo=105, Remark="代码生成打印类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-12-04 00:00:00") }, new SysDictType{ Id=1300000000106, Name="代码生成打印类型", Code="code_gen_print_type", SysFlag=YesNoEnum.Y, OrderNo=105, Remark="代码生成打印类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-12-04 00:00:00") },
new SysDictType{ Id=1300000000201, Name="机构类型", Code="org_type", OrderNo=201, Remark="机构类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") }, new SysDictType{ Id=1300000000201, Name="机构类型", Code="org_type", SysFlag=YesNoEnum.Y, OrderNo=201, Remark="机构类型", Status=StatusEnum.Enable, CreateTime=DateTime.Parse("2023-02-10 00:00:00") },
]; ];
} }
} }

View File

@ -14,10 +14,13 @@ public class SysDictDataService : IDynamicApiController, ITransient
{ {
private readonly SqlSugarRepository<SysDictData> _sysDictDataRep; private readonly SqlSugarRepository<SysDictData> _sysDictDataRep;
private readonly SysCacheService _sysCacheService; private readonly SysCacheService _sysCacheService;
private readonly UserManager _userManager;
public SysDictDataService(SqlSugarRepository<SysDictData> sysDictDataRep, public SysDictDataService(SqlSugarRepository<SysDictData> sysDictDataRep,
SysCacheService sysCacheService) SysCacheService sysCacheService,
UserManager userManager)
{ {
_userManager = userManager;
_sysDictDataRep = sysDictDataRep; _sysDictDataRep = sysDictDataRep;
_sysCacheService = sysCacheService; _sysCacheService = sysCacheService;
} }
@ -34,7 +37,7 @@ public class SysDictDataService : IDynamicApiController, ITransient
.Where(u => u.DictTypeId == input.DictTypeId) .Where(u => u.DictTypeId == input.DictTypeId)
.WhereIF(!string.IsNullOrEmpty(input.Code?.Trim()), u => u.Code.Contains(input.Code)) .WhereIF(!string.IsNullOrEmpty(input.Code?.Trim()), u => u.Code.Contains(input.Code))
.WhereIF(!string.IsNullOrEmpty(input.Value?.Trim()), u => u.Value.Contains(input.Value)) .WhereIF(!string.IsNullOrEmpty(input.Value?.Trim()), u => u.Value.Contains(input.Value))
.OrderBy(u => new { u.OrderNo, u.Code }) .OrderBy(u => new { u.TenantId, u.OrderNo, u.Code })
.ToPagedListAsync(input.Page, input.PageSize); .ToPagedListAsync(input.Page, input.PageSize);
} }
@ -60,9 +63,10 @@ public class SysDictDataService : IDynamicApiController, ITransient
var isExist = await _sysDictDataRep.IsAnyAsync(u => u.Code == input.Code && u.DictTypeId == input.DictTypeId); var isExist = await _sysDictDataRep.IsAnyAsync(u => u.Code == input.Code && u.DictTypeId == input.DictTypeId);
if (isExist) throw Oops.Oh(ErrorCodeEnum.D3003); if (isExist) throw Oops.Oh(ErrorCodeEnum.D3003);
var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == input.DictTypeId).Select(u => u.DictType.Code).FirstAsync(); var dictType = await _sysDictDataRep.Change<SysDictType>().GetByIdAsync(input.DictTypeId);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}"); if (dictType.SysFlag == YesNoEnum.Y && !_userManager.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D3008);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictType.Code}");
await _sysDictDataRep.InsertAsync(input.Adapt<SysDictData>()); await _sysDictDataRep.InsertAsync(input.Adapt<SysDictData>());
} }
@ -82,9 +86,10 @@ public class SysDictDataService : IDynamicApiController, ITransient
isExist = await _sysDictDataRep.IsAnyAsync(u => u.Code == input.Code && u.DictTypeId == input.DictTypeId && u.Id != input.Id); isExist = await _sysDictDataRep.IsAnyAsync(u => u.Code == input.Code && u.DictTypeId == input.DictTypeId && u.Id != input.Id);
if (isExist) throw Oops.Oh(ErrorCodeEnum.D3003); if (isExist) throw Oops.Oh(ErrorCodeEnum.D3003);
var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == input.DictTypeId).Select(u => u.DictType.Code).FirstAsync(); var dictType = await _sysDictDataRep.Change<SysDictType>().GetByIdAsync(input.DictTypeId);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}"); if (dictType.SysFlag == YesNoEnum.Y && !_userManager.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D3009);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictType.Code}");
await _sysDictDataRep.UpdateAsync(input.Adapt<SysDictData>()); await _sysDictDataRep.UpdateAsync(input.Adapt<SysDictData>());
} }
@ -100,9 +105,10 @@ public class SysDictDataService : IDynamicApiController, ITransient
{ {
var dictData = await _sysDictDataRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3004); var dictData = await _sysDictDataRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3004);
var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == dictData.Id).Select(u => u.DictType.Code).FirstAsync(); var dictType = await _sysDictDataRep.Change<SysDictType>().GetByIdAsync(dictData.DictTypeId);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}"); if (dictType.SysFlag == YesNoEnum.Y && !_userManager.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D3010);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictType.Code}");
await _sysDictDataRep.DeleteAsync(dictData); await _sysDictDataRep.DeleteAsync(dictData);
} }
@ -128,8 +134,10 @@ public class SysDictDataService : IDynamicApiController, ITransient
{ {
var dictData = await _sysDictDataRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3004); var dictData = await _sysDictDataRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3004);
var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == dictData.Id).Select(u => u.DictType.Code).FirstAsync(); var dictType = await _sysDictDataRep.Change<SysDictType>().GetByIdAsync(dictData.DictTypeId);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}"); if (dictType.SysFlag == YesNoEnum.Y && !_userManager.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D3009);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictType.Code}");
dictData.Status = input.Status; dictData.Status = input.Status;
await _sysDictDataRep.AsUpdateable(dictData).UpdateColumns(u => new { u.Status }, true).ExecuteCommandAsync(); await _sysDictDataRep.AsUpdateable(dictData).UpdateColumns(u => new { u.Status }, true).ExecuteCommandAsync();
@ -143,12 +151,14 @@ public class SysDictDataService : IDynamicApiController, ITransient
[NonAction] [NonAction]
public async Task<List<SysDictData>> GetDictDataListByDictTypeId(long dictTypeId) public async Task<List<SysDictData>> GetDictDataListByDictTypeId(long dictTypeId)
{ {
var dictType = await _sysDictDataRep.ChangeRepository<SqlSugarRepository<SysDictType>>().GetByIdAsync(dictTypeId); var dictType = await _sysDictDataRep.Change<SysDictType>().GetByIdAsync(dictTypeId);
var dictDataList = _sysCacheService.Get<List<SysDictData>>($"{CacheConst.KeyDict}{dictTypeId}"); var dictDataList = _sysCacheService.Get<List<SysDictData>>($"{CacheConst.KeyDict}{dictType.Code}");
if (dictDataList == null) if (dictDataList == null)
{ {
dictDataList = await _sysDictDataRep.AsQueryable() dictDataList = await _sysDictDataRep.AsQueryable().ClearFilter()
.InnerJoin<SysDictType>((u , a) => u.DictTypeId == a.Id)
.Where((u, a) => a.SysFlag == YesNoEnum.Y || u.TenantId == _userManager.TenantId)
.Where(u => u.DictTypeId == dictTypeId).OrderBy(u => new { u.OrderNo, u.Code }).ToListAsync(); .Where(u => u.DictTypeId == dictTypeId).OrderBy(u => new { u.OrderNo, u.Code }).ToListAsync();
_sysCacheService.Set($"{CacheConst.KeyDict}{dictType.Code}", dictDataList); _sysCacheService.Set($"{CacheConst.KeyDict}{dictType.Code}", dictDataList);
} }
@ -166,8 +176,9 @@ public class SysDictDataService : IDynamicApiController, ITransient
var dictDataList = _sysCacheService.Get<List<SysDictData>>($"{CacheConst.KeyDict}{code}"); var dictDataList = _sysCacheService.Get<List<SysDictData>>($"{CacheConst.KeyDict}{code}");
if (dictDataList == null) if (dictDataList == null)
{ {
dictDataList = await _sysDictDataRep.Context.Queryable<SysDictType>() dictDataList = await _sysDictDataRep.Change<SysDictType>().AsQueryable()
.LeftJoin<SysDictData>((u, a) => u.Id == a.DictTypeId) .LeftJoin<SysDictData>((u, a) => u.Id == a.DictTypeId).ClearFilter()
.Where((u, a) => u.SysFlag == YesNoEnum.Y || a.TenantId == _userManager.TenantId)
.Where((u, a) => u.Code == code && u.Status == StatusEnum.Enable && a.Status == StatusEnum.Enable) .Where((u, a) => u.Code == code && u.Status == StatusEnum.Enable && a.Status == StatusEnum.Enable)
.OrderBy((u, a) => new { a.OrderNo, a.Code }) .OrderBy((u, a) => new { a.OrderNo, a.Code })
.Select((u, a) => a).ToListAsync(); .Select((u, a) => a).ToListAsync();
@ -184,10 +195,11 @@ public class SysDictDataService : IDynamicApiController, ITransient
[DisplayName("根据查询条件获取字典值集合")] [DisplayName("根据查询条件获取字典值集合")]
public async Task<List<SysDictData>> GetDataList([FromQuery] QueryDictDataInput input) public async Task<List<SysDictData>> GetDataList([FromQuery] QueryDictDataInput input)
{ {
return await _sysDictDataRep.Context.Queryable<SysDictType>() return await _sysDictDataRep.Change<SysDictType>().AsQueryable()
.LeftJoin<SysDictData>((u, a) => u.Id == a.DictTypeId) .LeftJoin<SysDictData>((u, a) => u.Id == a.DictTypeId).ClearFilter()
.Where((u, a) => u.SysFlag == YesNoEnum.Y || a.TenantId == _userManager.TenantId)
.Where((u, a) => u.Code == input.Code) .Where((u, a) => u.Code == input.Code)
.WhereIF(input.Status.HasValue, (u, a) => a.Status == (StatusEnum)input.Status.Value) .WhereIF(input.Status.HasValue, (u, a) => u.Status == (StatusEnum)input.Status.Value && a.Status == (StatusEnum)input.Status.Value)
.OrderBy((u, a) => new { a.OrderNo, a.Code }) .OrderBy((u, a) => new { a.OrderNo, a.Code })
.Select((u, a) => a).ToListAsync(); .Select((u, a) => a).ToListAsync();
} }

View File

@ -15,14 +15,17 @@ public class SysDictTypeService : IDynamicApiController, ITransient
private readonly SqlSugarRepository<SysDictType> _sysDictTypeRep; private readonly SqlSugarRepository<SysDictType> _sysDictTypeRep;
private readonly SysDictDataService _sysDictDataService; private readonly SysDictDataService _sysDictDataService;
private readonly SysCacheService _sysCacheService; private readonly SysCacheService _sysCacheService;
private readonly UserManager _userManager;
public SysDictTypeService(SqlSugarRepository<SysDictType> sysDictTypeRep, public SysDictTypeService(SqlSugarRepository<SysDictType> sysDictTypeRep,
SysDictDataService sysDictDataService, SysDictDataService sysDictDataService,
SysCacheService sysCacheService) SysCacheService sysCacheService,
UserManager userManager)
{ {
_sysDictTypeRep = sysDictTypeRep; _sysDictTypeRep = sysDictTypeRep;
_sysDictDataService = sysDictDataService; _sysDictDataService = sysDictDataService;
_sysCacheService = sysCacheService; _sysCacheService = sysCacheService;
_userManager = userManager;
} }
/// <summary> /// <summary>
@ -33,6 +36,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
public async Task<SqlSugarPagedList<SysDictType>> Page(PageDictTypeInput input) public async Task<SqlSugarPagedList<SysDictType>> Page(PageDictTypeInput input)
{ {
return await _sysDictTypeRep.AsQueryable() return await _sysDictTypeRep.AsQueryable()
.WhereIF(!_userManager.SuperAdmin, u => u.SysFlag == YesNoEnum.N)
.WhereIF(!string.IsNullOrEmpty(input.Code?.Trim()), u => u.Code.Contains(input.Code)) .WhereIF(!string.IsNullOrEmpty(input.Code?.Trim()), u => u.Code.Contains(input.Code))
.WhereIF(!string.IsNullOrEmpty(input.Name?.Trim()), u => u.Name.Contains(input.Name)) .WhereIF(!string.IsNullOrEmpty(input.Name?.Trim()), u => u.Name.Contains(input.Name))
.OrderBy(u => new { u.OrderNo, u.Code }) .OrderBy(u => new { u.OrderNo, u.Code })
@ -72,6 +76,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
public async Task AddDictType(AddDictTypeInput input) public async Task AddDictType(AddDictTypeInput input)
{ {
if (input.Code.ToLower().EndsWith("enum")) throw Oops.Oh(ErrorCodeEnum.D3006); if (input.Code.ToLower().EndsWith("enum")) throw Oops.Oh(ErrorCodeEnum.D3006);
if (input.SysFlag == YesNoEnum.Y && !_userManager.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D3008);
var isExist = await _sysDictTypeRep.IsAnyAsync(u => u.Code == input.Code); var isExist = await _sysDictTypeRep.IsAnyAsync(u => u.Code == input.Code);
if (isExist) throw Oops.Oh(ErrorCodeEnum.D3001); if (isExist) throw Oops.Oh(ErrorCodeEnum.D3001);
@ -93,6 +98,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
if (dict == null) throw Oops.Oh(ErrorCodeEnum.D3000); if (dict == null) throw Oops.Oh(ErrorCodeEnum.D3000);
if (dict.Code.ToLower().EndsWith("enum") && input.Code != dict.Code) throw Oops.Oh(ErrorCodeEnum.D3007); if (dict.Code.ToLower().EndsWith("enum") && input.Code != dict.Code) throw Oops.Oh(ErrorCodeEnum.D3007);
if (input.SysFlag == YesNoEnum.Y && !_userManager.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D3009);
var isExist = await _sysDictTypeRep.IsAnyAsync(u => u.Code == input.Code && u.Id != input.Id); var isExist = await _sysDictTypeRep.IsAnyAsync(u => u.Code == input.Code && u.Id != input.Id);
if (isExist) throw Oops.Oh(ErrorCodeEnum.D3001); if (isExist) throw Oops.Oh(ErrorCodeEnum.D3001);
@ -112,6 +118,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
public async Task DeleteDictType(DeleteDictTypeInput input) public async Task DeleteDictType(DeleteDictTypeInput input)
{ {
var dictType = await _sysDictTypeRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3000); var dictType = await _sysDictTypeRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3000);
if (dictType.SysFlag == YesNoEnum.Y && !_userManager.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D3010);
// 删除字典值 // 删除字典值
await _sysDictTypeRep.DeleteAsync(dictType); await _sysDictTypeRep.DeleteAsync(dictType);
@ -139,6 +146,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
public async Task SetStatus(DictTypeInput input) public async Task SetStatus(DictTypeInput input)
{ {
var dictType = await _sysDictTypeRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3000); var dictType = await _sysDictTypeRep.GetByIdAsync(input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D3000);
if (dictType.SysFlag == YesNoEnum.Y && !_userManager.SuperAdmin) throw Oops.Oh(ErrorCodeEnum.D3009);
_sysCacheService.Remove($"{CacheConst.KeyDict}{dictType.Code}"); _sysCacheService.Remove($"{CacheConst.KeyDict}{dictType.Code}");
@ -154,8 +162,9 @@ public class SysDictTypeService : IDynamicApiController, ITransient
public async Task<dynamic> GetAllDictList() public async Task<dynamic> GetAllDictList()
{ {
var ds = await _sysDictTypeRep.AsQueryable() var ds = await _sysDictTypeRep.AsQueryable()
.InnerJoin<SysDictData>((u, a) => u.Id == a.DictTypeId) .InnerJoin<SysDictData>((u, a) => u.Id == a.DictTypeId).ClearFilter()
.Where((u, a) => u.IsDelete == false && a.IsDelete == false && a.Status == StatusEnum.Enable) .Where((u, a) => u.SysFlag == YesNoEnum.Y || a.TenantId == _userManager.TenantId)
.Where((u, a) => u.IsDelete == false && a.IsDelete == false && u.Status == StatusEnum.Enable && a.Status == StatusEnum.Enable)
.Select((u, a) => new { TypeCode = u.Code, a.Code, a.Name, a.Value, a.Remark, a.OrderNo, a.TagType, a.ExtData }) .Select((u, a) => new { TypeCode = u.Code, a.Code, a.Name, a.Value, a.Remark, a.OrderNo, a.TagType, a.ExtData })
.ToListAsync(); .ToListAsync();
return ds.OrderBy(u => u.OrderNo).GroupBy(u => u.TypeCode).ToDictionary(u => u.Key, u => u); return ds.OrderBy(u => u.OrderNo).GroupBy(u => u.TypeCode).ToDictionary(u => u.Key, u => u);