繁体   English   中英

NHibernate:拦截和修改查询参数?

[英]NHibernate: intercept and modify query parameters?

tldr:我可以在构造 select 查询时拦截查询参数并修改它们吗? 我找不到任何似乎能够做到这一点的事件侦听器或拦截器。 就我而言,我想在绑定之前检查所有查询参数,查找具有 Kind=Unspecified 的特定 DateTime 查询参数,并将它们的 Kind 设置为 Local。

编辑:用 IUserType 解决,见下文


在 BIG 版本升级(3.4 到 5.3)之后,我遇到了通过映射为 LocalDateTimeType 的 DateTime 属性查询实体的问题。 实体映射的简化示例,部分和通过 DateTime 属性查询的用例:

public class MyEntity {
    ...
    public virtual DateTime EntityDate { get; set; }
    ...
}
public class MyEntityMap : ClassMap<MyEntity> {
    public MyEntityMap() {
        ...
        Map(x => x.EntityDate).Column("entitydate").Not.Nullable().CustomType<LocalDateTimeType>();
        ...
    }
}
...
public IEnumerable<MyEntity> FindAllBeforeDate(DateTime date) {
    return session.QueryOver<MyEntity>().Where(x => x.EntityDate < date).List();
}

代码库有许多其他用于查询此属性的用例,使用 QueryOver、Criteria 查询和 HQL 实现。 在任何情况下,升级后这些查询都会引发异常:

LocalDateTime expect date kind Local but it is Unspecified\r\nParameter name: value
at NHibernate.Type.AbstractDateTimeType.Set(DbCommand st, Object value, Int32 index, ISessionImplementor session)
   at NHibernate.Param.NamedParameterSpecification.Bind(DbCommand command, IList`1 multiSqlQueryParametersList, Int32 singleSqlParametersOffset, IList`1 sqlQueryParametersList, QueryParameters queryParameters, ISessionImplementor session)
   at NHibernate.Param.NamedParameterSpecification.Bind(DbCommand command, IList`1 sqlQueryParametersList, QueryParameters queryParameters, ISessionImplementor session)
   at NHibernate.SqlCommand.SqlCommandImpl.Bind(DbCommand command, ISessionImplementor session)
   at NHibernate.Loader.Loader.PrepareQueryCommand(QueryParameters queryParameters, Boolean scroll, ISessionImplementor session)
   at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies, IResultTransformer forcedResultTransformer, QueryCacheResultBuilder queryCacheResultBuilder)
   at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies, IResultTransformer forcedResultTransformer, QueryCacheResultBuilder queryCacheResultBuilder)
   at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters, IResultTransformer forcedResultTransformer, QueryCacheResultBuilder queryCacheResultBuilder)

换句话说,我试图通过 EntityDate 使用具有 DateTimeKind=Unspecified 的参数 DateTime 值进行查询。 nHibernate 现在强制参数值必须具有 DateTimeKind=Local 对于任何 LocalDateTimeType 属性; 所以查询生成器不会绑定我的参数值。

我可以 go 通过应用程序中查询此属性(有很多)的每个位置并单独修复每个位置。 但这很糟糕,在我看来。 如何拦截或侦听在参数绑定过程之前定位的事件,查找使用错误参数值查询“entitydate”的实例,并修复参数值以具有正确的 DateTimeKind? 我找不到任何似乎能够做到这一点的拦截器或事件监听器。

原来我正在查看 API 的错误部分,这是使用自定义用户类型而不是事件侦听器或拦截器解决的。 自定义类型是 IUserType 的实现,它包装 DateTime 并强制将映射到该类型的 DbCommand 的任何参数转换为具有 DateTimeKind.Local。

[Serializable]
public class LocalKindDateTimeType : IUserType
{
    public SqlType[] SqlTypes => new SqlType[]
    {
        new SqlType(DbType.DateTime)
    };

    public Type ReturnedType => typeof(DateTime);

    public bool IsMutable => false;

    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y))
        {
            return true;
        }

        if (x == null || y == null)
        {
            return false;
        }

        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public object NullSafeGet(DbDataReader rs, string[] names, ISessionImplementor session, object owner)
    {
        if (owner == null)
            return null;
        return DateTime.SpecifyKind((DateTime)NHibernateUtil.DateTime.NullSafeGet(rs, names, session), DateTimeKind.Local);
    }

    public void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session)
    {
        if (value is DateTime date)
            NHibernateUtil.DateTime.NullSafeSet(cmd, DateTime.SpecifyKind(date, DateTimeKind.Local), index, session);
        else
            NHibernateUtil.DateTime.NullSafeSet(cmd, value, index, session);
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM