簡體   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