2009-05-21 7 views
2

私はASP.NET MVCアプリケーションの高度な検索フォームを構築しています。高度な検索のためのコンポーネントとコレクションを含むNHibernate ICriteriaクエリ

私はアドレスのコンポーネントで、Customerオブジェクトを持っている: 流暢NHibernateのマッピング:nullのオブジェクトを防ぐために、私の顧客クラスのctorで

 public CustomerMap() 
    { 
     WithTable("Customers"); 

     Id(x => x.Id) 
      .WithUnsavedValue(0) 
      .GeneratedBy.Identity(); 

     Map(x => x.Name); 
     Map(x => x.Industry); 

     Component(x => x.Address, m => 
     { 
      m.Map(x => x.AddressLine); 
      m.Map(x => x.City); 
      m.Map(x => x.State); 
      m.Map(x => x.Zip); 
     }); 

、私は次のようしている:

public Customer() 
{ 
    Address = new Address(); 
} 

私の検索フォームには、ユーザーが検索するために利用できる次のフィールドがあります。

  • Cus tomer名前
  • 産業

これらのフィールドはすべてオプションです。私はヌルを排除するために().ExcludeZeroesを使用してい

  var p = Session.CreateCriteria(typeof(Customer)) 
      .Add(Example.Create(customer).ExcludeZeroes().IgnoreCase().EnableLike()) 
      .SetProjection(Projections.ProjectionList() 
           .Add(Projections.Property("Id"), "Id") 
           .Add(Projections.Property("Name"), "Name") 
           .Add(Projections.Property("Address.City"), "City") 
           .Add(Projections.Property("Address.State"), "State") 
           .Add(Projections.Property("PhoneNumber"), "PhoneNumber")) 
      .AddOrder(Order.Asc("Name")) 
      .SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean(typeof(CustomerDTO))); 

     return p.List<CustomerDTO>() as List<CustomerDTO>; 

お知らせ:

私のNHibernateの基準は、(顧客がASP.NET MVCモデルバインダーを使用して、フォームから渡されている)、このようになります。デフォルト値はゼロです。これは、私のCustomerオブジェクトにはクエリがゼロ(0)にデフォルト設定されるいくつかのINT(簡潔さのためにこの記事では除外されている)があり、不正確なクエリが発生するため必須です。

私は(彼らはオプションなので、OK)空白のすべてのフィールドでこれを実行すると、結果のSQLは次のようになります。

SELECT this_.Id   as y0_, 
     this_.Name  as y1_, 
     this_.City  as y2_, 
     this_.State  as y3_, 
     this_.PhoneNumber as y4_ 
FROM  Customers this_ 
WHERE (lower(this_.Industry) like '' /* @p0 */ 
      and lower(this_.State) like '' /* @p1 */) 
ORDER BY y1_ asc 

産業と国家は、Webフォームにドロップダウンしているが、上の例では、それらを空白のままにしました。しかし、ExcludeZeroes()宣言はこれらのフィールドには当てはまらないようです。私は手動で基準の前にチェックした場合

if (customer.Address.State == "") 
{ 
    customer.Address.State = null; 
} 

産業のための同じことを行う、基準は、動作します。

私はこのことが私の顧客のアドレスオブジェクトを初期化していると仮定しています。私はそれを変更することはできませんが、フォームから空の文字列値を手動でチェックすることなく、Criteriaを動作させる別の方法はわかりません(ICriteriaでExampleオブジェクトを使用する利点を排除します)。

なぜですか?このCriteriaクエリを機能させるにはどうすればよいですか?

+0

あなたはクエリの例と結婚していますか? –

+0

詳細な検索フォームの場合は、コードをより柔軟にしますが、正確ではありません。私は空の文字列のコンポーネントをチェックしてnullsに変更し、それが動作する場合上記のコードが動作することができます。私はHQLを使用して動作させることもできますが、必要以上に醜いと思われます。私は、QBEが不要なチェックでコードを捨てることなく動作することを期待していました。 –

答えて

1

プロパティセレクタを使用して、nullまたは空の文字列を無視します。

using System; 
using NHibernate.Criterion; 
using NHibernate.Type; 


namespace Sample 
{ 

    /// <summary> 
    /// Implementation of <see cref="Example.IPropertySelector"/> that includes the 
    /// properties that are not <c>null</c> and do not have an <see cref="String.Empty"/> 
    /// returned by <c>propertyValue.ToString()</c>. 
    /// </summary> 
    /// <remarks> 
    /// This selector is not present in H2.1. It may be useful if nullable types 
    /// are used for some properties. 
    /// </remarks> 
    public class NoValuePropertySelector : Example.IPropertySelector 
    { 
     #region [ Methods (2) ] 

     // [ Public Methods (1) ] 

     /// <summary> 
     /// Determine if the Property should be included. 
     /// </summary> 
     /// <param name="propertyValue">The value of the property that is being checked for inclusion.</param> 
     /// <param name="propertyName">The name of the property that is being checked for inclusion.</param> 
     /// <param name="type">The <see cref="T:NHibernate.Type.IType"/> of the property.</param> 
     /// <returns> 
     ///  <see langword="true"/> if the Property should be included in the Query, 
     /// <see langword="false"/> otherwise. 
     /// </returns> 
     public bool Include(object propertyValue, String propertyName, IType type) 
     { 
      if (propertyValue == null) 
      { 
       return false; 
      } 

      if (propertyValue is string) 
      { 
       return ((string)propertyValue).Length != 0; 
      } 

      if (IsZero(propertyValue)) 
      { 
       return false; 
      } 
      else 
      { 
       return true; 
      } 
     } 

     // [ Private Methods (1) ] 

     private static bool IsZero(object value) 
     { 
      // Only try to check IConvertibles, to be able to handle various flavors 
      // of nullable numbers, etc. Skip strings. 
      if (value is IConvertible && !(value is string)) 
      { 
       try 
       { 
        return Convert.ToInt64(value) == 0L; 
       } 
       catch (FormatException) 
       { 
        // Ignore 
       } 
       catch (InvalidCastException) 
       { 
        // Ignore 
       } 
      } 

      return false; 
     } 


     #endregion [ Methods ] 
    } 

} 
0

私はQBEで同じ問題があります。私はまた、Query by Exampleはオブジェクト(および関連するもの)に対する汎用検索のための非常に良いアプローチだと考えています。既にExcludeNones/Nulls/Zerosがあります。空の文字列( "")も除外するオプションが必要です。

関連する問題