C# 实体框架核心中的属性/列级访问
在这个问题上,我问了一种在.NET5中实现属性/字段级访问的方法。一个想法是在EF核心配置中发挥神奇的作用,这样只有那些属性才能从当前用户有权访问的数据库中加载。在第二步中,将使用带有默认条件的C# 实体框架核心中的属性/列级访问,c#,entity-framework-core,authorization,.net-5,role-base-authorization,C#,Entity Framework Core,Authorization,.net 5,Role Base Authorization,在这个问题上,我问了一种在.NET5中实现属性/字段级访问的方法。一个想法是在EF核心配置中发挥神奇的作用,这样只有那些属性才能从当前用户有权访问的数据库中加载。在第二步中,将使用带有默认条件的JsonIgnore属性从dto中排除空属性。我已经尽了最大努力,使用实体属性上的自定义属性在上下文的OnModelCreating钩子中实现了逻辑: public class MyEntity : BaseEntity { [IncludeForRoles(RoleNames.Staff)]
JsonIgnore
属性从dto中排除空属性。我已经尽了最大努力,使用实体属性上的自定义属性在上下文的OnModelCreating
钩子中实现了逻辑:
public class MyEntity : BaseEntity
{
[IncludeForRoles(RoleNames.Staff)]
public string InternalDetails { get; private set; }
}
public class MyContext : IdentityDbContext<User, Role, Guid>, IMyContext
{
private readonly ITokenAccessor _tokenAccessor;
public MyContext(
DbContextOptions options,
ITokenAccessor tokenAccessor) : base(options)
{
_tokenAccessor = tokenAccessor;
}
[...]
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfigurationsFromAssembly(typeof(UserConfiguration).Assembly);
foreach (Type type in MyContextUtility.GetEntityTypes())
{
MethodInfo ignoreFlagMethod = MyContextUtility.SetRoleBasedIgnoreFlagMethod.MakeGenericMethod(type);
ignoreFlagMethod.Invoke(this, new object[] { builder, _tokenAccessor.UserRoles });
}
}
}
public static class MyContextUtility
{
private static IList<Type> _entityTypeCache;
public static IList<Type> GetEntityTypes()
{
if (_entityTypeCache != null)
{
return _entityTypeCache.ToList();
}
Assembly assembly = typeof(BaseEntity).Assembly;
_entityTypeCache = (from t in assembly.DefinedTypes
where t.BaseType == typeof(BaseEntity)
select t.AsType()).ToList();
return _entityTypeCache;
}
public static readonly MethodInfo SetRoleBasedIgnoreFlagMethod
= typeof(MyContextUtility).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Single(t => t.IsGenericMethod && t.Name == nameof(SetRoleBasedIgnoreFlag));
public static void SetRoleBasedIgnoreFlag<T>(ModelBuilder builder, IList<string> userRoles) where T : BaseEntity
{
IEnumerable<PropertyInfo> props = typeof(T).GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(IncludeForRolesAttribute)));
foreach (PropertyInfo prop in props)
{
IncludeForRolesAttribute attr = prop.GetCustomAttribute<IncludeForRolesAttribute>();
if (!userRoles.Intersect(attr.RoleNames).Any())
{
Debug.WriteLine($"Adding ignore flag for type '{typeof(T).Name}' and property {prop.Name}.");
builder.Entity<T>().Ignore(prop.Name);
}
}
}
}
公共类MyEntity:BaseEntity
{
[包括错误(RoleNames.Staff)]
公共字符串InternalDetails{get;private set;}
}
公共类MyContext:IdentityDbContext,IMyContext
{
专用只读ITokenAccessor\u令牌访问器;
公共MyContext(
DbContextOptions选项,
ITokenAccessor tokenAccessor):基本(选项)
{
_令牌访问器=令牌访问器;
}
[...]
模型创建时受保护的覆盖无效(ModelBuilder)
{
基于模型创建(生成器);
builder.ApplyConfigurationsFromAssembly(typeof(UserConfiguration).Assembly);
foreach(myContextity.GetEntityTypes()中的类型)
{
MethodInfo ignoreFlagMethod=MyContextivity.SetRoleBasedIgnoreFlagMethod.MakeGenericMethod(类型);
Invoke(这是一个新对象[]{builder,_tokenAccessor.UserRoles});
}
}
}
公共静态类myContextivity
{
私有静态IList_entityTypeCache;
公共静态IList GetEntityTypes()
{
if(_entityTypeCache!=null)
{
返回_entityTypeCache.ToList();
}
Assembly Assembly=typeof(BaseEntity).Assembly;
_entityTypeCache=(来自assembly.DefinedTypes中的t
其中t.BaseType==typeof(BaseEntity)
选择t.AsType()).ToList();
返回_entityTypeCache;
}
公共静态只读方法信息SetRoleBasedIgnoreFlagMethod
=typeof(myContextivity).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Single(t=>t.IsGenericMethod&&t.Name==nameof(SetRoleBasedIgnoreFlag));
公共静态void SetRoleBasedIgnoreFlag(ModelBuilder,IList userRoles),其中T:BaseEntity
{
IEnumerable props=typeof(T).GetProperties()。其中(
prop=>Attribute.IsDefined(prop,typeof(includeErrorsAttribute));
foreach(PropertyInfo props in props)
{
includeErrorsAttribute attr=prop.GetCustomAttribute();
如果(!userRoles.Intersect(attr.RoleNames).Any())
{
WriteLine($“为类型{typeof(T.Name}'和属性{prop.Name}添加忽略标志”);
builder.Entity().Ignore(prop.Name);
}
}
}
}
ITokenAccessor
提供对当前用户的jwt访问令牌的访问。
上面的代码不起作用,因为OnModelCreating
是在用户登录之前执行的,这就是\u tokenAccessor.UserRoles
此时始终为空的原因
是否有一种方法可以在实体框架核心中实现基于属性/列的访问?我花了几个小时研究,但不幸的是找不到解决办法。我很惊讶基于属性/列的访问竟然是如此不同寻常的要求。您是使用Automapper还是让实体通过网络访问?问:因为您正朝着错误的方向移动。我使用automapper将实体映射到dtosWell,为什么不创建automapper配置以消除不需要的属性?这是一个选项,是的。但是如何将ITokenAccessor注入到映射配置文件中呢?缺点是,使用这种方法,我们从数据库加载最终不需要的数据。另一个缺点是,如果您使用ProjectTo,那么我们必须在多个位置(对于每个概要文件)实现逻辑-它不会加载不需要的属性。