Хорошо, у меня есть тонна вопросов, заданных здесь, но ни одна из них не решит эту проблему полностью или правильно.Linq to Entities и литье сложного типа
Давайте предположим, что у меня есть следующий код ...
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();
}
в этому методу я хочу добавить проверку что может привести меня динамически добавляя простой, где положение моей 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)));
}
... Это достаточно просто, где предложение в его собственном праве, и если бы я знал, что Т был во время разработки, это было бы проблемой.
Однако, отбрасывая result
к IQueryable<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
EDIT: Некоторые испытанные реализации ...
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;
}