C# 实体框架核心中的属性/列级访问

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)]

在这个问题上,我问了一种在.NET5中实现属性/字段级访问的方法。一个想法是在EF核心配置中发挥神奇的作用,这样只有那些属性才能从当前用户有权访问的数据库中加载。在第二步中,将使用带有默认条件的
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,那么我们必须在多个位置(对于每个概要文件)实现逻辑-它不会加载不需要的属性。