2009-05-21 7 views
2

Ich erstelle ein erweitertes Suchformular für meine ASP.NET MVC App.NHibernate ICriteria Abfrage mit Komponenten und Sammlungen für die erweiterte Suche

ich ein Customer-Objekt haben, mit einer Adresse Komponente: Fluent NHibernate-Mapping:

 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); 
     }); 

In meinem Customer-Klasse ctor, null Objekte zu verhindern, habe ich folgendes:

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

Mein Suchformular hat die folgenden Felder, die der Benutzer durchsuchen kann:

  • Cus Tomer Namen
  • Stadt
  • Staat
  • Industrie

Alle diese Felder sind optional.

Meine NHibernate Criteria sieht wie folgt aus (Kunde aus dem Formular übergeben wird, um die ASP.NET MVC Modell Binder verwendet wird):

  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>; 

Beachten Sie, dass ich .ExcludeZeroes bin mit() NULL-Werte auszuschließen und Null-Standardwerte. Dies ist erforderlich, da mein Customer-Objekt einige INTs enthält (in dieser Veröffentlichung aus Platzgründen ausgeschlossen), die in der Abfrage standardmäßig auf null (0) gesetzt würden, was zu inkorrekten Abfragen führen würde.

Wenn ich betreiben diese mit allen Feldern leer (ok, da sie optional sind), die resultierenden SQL wie folgt aussehen:

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 

Industrie und Staat ist Drop-downs in dem Web-Formular, aber Im obigen Beispiel habe ich sie leer gelassen. Aber die ExcludeZeroes() - Deklaration scheint nicht für diese Felder zu gelten.

Wenn ich manuell vor den Kriterien überprüfen:

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

und das gleiche für Industrie, werden die Kriterien dann arbeiten.

Ich gehe davon aus, dass dies mit mir zu tun hat, das Adressobjekt in meinem Kunden ctor initialisieren. Ich hasse es, dies zu ändern, aber ich kenne keine andere Möglichkeit, die Kriterien zu erfüllen, ohne manuell nach leeren Zeichenfolgenwerten aus dem Formular zu suchen (wodurch der Vorteil beseitigt wird, ein Beispielobjekt mit ICriteria zu verwenden).

Warum? Wie kann ich diese Kriterienabfrage ausführen?

+0

Sind Sie mit Query By Example verheiratet? –

+0

Nicht genau, obwohl es den Code im Falle eines erweiterten Suchformulars flexibler macht. Ich kann den obigen Code funktionieren lassen, wenn ich die Komponente auf leere Zeichenfolge überprüfe und sie in Nullen umwandle, und es funktioniert. Ich kann auch HQL verwenden und es funktioniert, aber es scheint hässlicher als notwendig. Ich hoffte, dass QBE funktionieren würde, ohne den Code mit unnötigen Überprüfungen zu überfrachten. –

Antwort

1

Verwenden Sie eine Eigenschaftenauswahl, um leere oder leere Zeichenfolgen zu ignorieren.

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

Ich habe das gleiche Problem mit QBE. Ich denke auch, dass die Query by Example ein sehr netter Ansatz für generische Suchen an einem Objekt (und assoziierten) ist. Es gibt bereits ExcludeNones/Nulls/Zeros. Es sollte auch eine Möglichkeit geben, leere Strings ("") auszuschließen.

Verwandte Themen