我的一些实体有window.onscroll = swapMenu;
接口。
我想检查存储库,如果实体实现接口,然后添加一些谓词。我有以下代码:
IEnabledEntity
但是,我对铸造有例外:
public class Repository<T> : IRepository<T> where T : class, IEntity, new()
{
public IQueryable<T> Get(Expression<Func<T, bool>> predicate, params string[] includes)
IQueryable<T> query = Context.Set<T>();
foreach (var include in includes)
{
query = query.Include(include);
}
query = query.Where(predicate);
var isEnabledEntity = typeof(IEnabledEntity).IsAssignableFrom(typeof(T));
if (isEnabledEntity)
{
query = query.Where(e => ((IEnabledEntity) e).IsEnabled);
}
return query;
}
public interface IEnabledEntity
{
bool IsEnabled { get; set; }
}
public class Test : IBaseEntity, IEnabledEntity
{
// ...
public bool IsEnabled { get; set; }
}
如何让它发挥作用?
答案 0 :(得分:2)
Linq-to-Entities只知道类的模型,这就是表达式不能包含接口类型的原因。但是,如果IsEnabled
实现了T
属性,那么访问IsAssignableFrom()
属性的运行时很明显,所以如果您自己检查ExpressionVisitor
(就像您一样),那么它就是“{1}}。可以使用internal class IgnoreCast : ExpressionVisitor
{
protected override Expression VisitUnary(UnaryExpression e)
{
if(e.NodeType == ExpressionType.Convert && e.Type.IsAssignableFrom(typeof(e.Operand))
return e.Operand;
else
return e;
}
}
类绕过转换:
IgnoreCast
然后,您需要使用extensionmethod创建过滤器,该方法实现internal static class LocalExtensions
{
internal static IgnoreCast ic = new IgnoreCast();
internal static IQueryable<T> FilterEnabled<T>(this IQueryable<T> query) where T: class
{
Expression<Func<T,bool>> expr = e => ((IEnabledEntity)e).IsEnabled;
expr = (Expression<Func<T,bool>>)ic.Visit(e);
return query.Where(expr);
}
}
类:
if(typeof(IEnabledEntity).IsAssignableFrom(T))
query = query.FilterEnabled();
然后你可以在程序中使用该方法:
Visit(Expression e)
基本方法Convert
会将表达式的每个节点传递给该类型节点的更专用的Visit方法。 UnaryExpression
nodetype是-- create field
ALTER TABLE users ADD COLUMN messages_total integer;
ALTER TABLE users ALTER COLUMN messages_total SET DEFAULT 0;
COMMENT ON COLUMN users.messages_total IS 'Users messages total.';
-- create trigger function
CREATE OR REPLACE FUNCTION "users_messages::update_statistics"()
RETURNS trigger AS
$BODY$BEGIN
IF TG_OP = 'DELETE' THEN
UPDATE users SET messages_total = messages_total - 1 WHERE id = OLD.user_id;
ELSIF TG_OP = 'INSERT' THEN
UPDATE users SET messages_total = messages_total + 1 WHERE id = NEW.user_id;
END IF;
RETURN NULL;
END;$BODY$
LANGUAGE plpgsql VOLATILE
COST 5;
CREATE TRIGGER update_statistics
AFTER INSERT OR DELETE
ON users_messages
FOR EACH ROW
EXECUTE PROCEDURE "users_messages::update_statistics"();
,因此此方法将在派生类中重写。如果unaryexpression是Convert nodetype并且操作数实现了类型,它将只返回操作数,从而删除了转换。
答案 1 :(得分:2)
IQueryable<T>
中的类型参数是协变的,因此不必担心在表达式中强制转换实体,只需安全地转换整个查询本身,然后使用Cast<T>()
将其恢复为实体类型:
public IQueryable<T> Get(Expression<Func<T, bool>> predicate, params string[] includes)
{
IQueryable<T> query = Context.Set<T>();
foreach (var include in includes)
{
query = query.Include(include);
}
query = query.Where(predicate);
var enabledQuery = query as IQueryable<IEnabledEntity>;
if (enabledQuery != null)
query = enabledQuery.Where(e => e.IsEnabled).Cast<T>();
return query;
}