c# - Linq to Entities 和复杂类型转换

标签 c# entity-framework linq casting

好吧,我在这里提出了很多此类性质的问题,但没有一个能够真正完全或正确地解决这个问题。

假设我有以下代码...

public interface IHaveRoles {
    ICollection<Role> Roles { get;set; }
}

public class Foo : IHaveRoles {  
    public ICollection<Role> Roles { get;set; }
}

public class Bar { }

...然后我有这样的方法...

public override IQueryable<T> GetAll()
{
    return base.GetAll();
}

在该方法中,我想添加一个检查,这可能会导致我动态地将一个简单的 where 子句添加到我的 IQueryable ...

if(typeof(IHaveRoles<Role>).IsAssignableFrom(typeof(T))) {
      return base.GetAll()
           .Where(i => i.Roles.Any(r => r.Users.Any(u => u.Id == User.Id)));

 }

... 它本身就是一个足够简单的 where 子句,如果我在设计时知道 T 是什么,那么这将不是问题。

但是,类型转换resultIQueryable<IHaveRoles>不是一个选项,因为当我附加完子句后,我无法再将其转换回 IQueryable<T>IHaveRoles不是 T 的子类型

那么我们如何解决这个问题,同时保留返回IQueryable<T>的能力并且没有非法强制转换,如其他问题中给出的一些答案所示......

Cast Entity to Implemented Interface in a Generic Method Using LINQ for Entity Framework

LINQ-to-entities casting issue

...并以某种方式避免 EF 不支持 EDM 基元类型的问题...

LINQ to Entities only supports casting EDM primitive or enumeration types with IEntity interface

编辑:一些经过测试的实现...

public override IQueryable<T> GetAll()
{
    var result = base.GetAll();

    if (typeof(IHaveRoles).IsAssignableFrom(typeof(T)) && !AuthInfo.SignatureIsValid)
    {
        // tried implementations that don't work ...

        // InvalidCastException (CLR can't cast an IQueryable<IHaveRoles> to a IQueryable<T>
        var queryableRoleSecured = ((IQueryable<IHaveRoles>)result);
        result = (IQueryable<T>)queryableRoleSecured
            .Where(i => i.Roles.Any(r => User.Roles.Contains(r)));

        // NotSupportedException (EF won't accept this kind of casting)
        result = result
            .Where(i => ((IHaveRoles)i).Roles.Any(r => r.Users.Any(u => u.Id == User.Id)));
    }

    return result;
}

最佳答案

哇,我似乎从来没有意识到动态 linq 似乎没有限制,但我们又来了。

这是我想到的......

public override IQueryable<T> GetAll()
{
    var result = base.GetAll();

    if (typeof(IHaveRoles).IsAssignableFrom(typeof(T)) && !AuthInfo.SignatureIsValid)
        result = result.Where("Roles.Any(Users.Any(Id == @0))", User.Id);

    return result;
}

因为动态是在运行时评估的,所以相同的设计时规则不适用,这意味着我可以应用我想要的完全相同的 linq(当然会有一点开销)。

关于c# - Linq to Entities 和复杂类型转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39618454/

相关文章:

c# - 尝试使用 ExecuteScalar ,并得到 "Specified cast is not valid "错误

c# - 在运行时切换 Process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden

c# - Linq按日期比较问题

c# - 如何使用 LINQ 将 .Where 添加到 .Select 到对象中?

c# - 具有不同类型的单排序C#列表?

c# - VS 项目引用因 GUID 区分大小写而损坏

c# - .Net Identity 中 UserManager 的奇怪行为

c# - IdentityDbContext 不从我的数据库初始值设定项调用种子方法

c# - 使用动态 linq 查询聚合函数 Count()

c# - 带别名的 Linq