2

我正在为我的 ASP.NET MVC 应用程序构建一个高级搜索表单。

我有一个 Customer 对象,带有一个地址组件:Fluent NHibernate 映射:

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

在我的 Customer 类 ctor 中,为了防止空对象,我有以下内容:

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

我的搜索表单有以下字段可供用户搜索:

  • 顾客姓名
  • 城市
  • 状态
  • 行业

所有的区域均为可选。

我的 NHibernate Criteria 看起来像这样(使用 ASP.NET MVC 模型绑定器从表单传入客户):

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

请注意,我使用 .ExcludeZeroes() 来排除空值和零默认值。这是必需的,因为我的 Customer 对象有一些 INT(为简洁起见在本文中排除),在查询中默认为零 (0),从而导致不正确的查询。

如果我在所有字段为空白的情况下运行此程序(好的,因为它们是可选的),则生成的 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

Industry 和 State 是 Web 表单中的下拉菜单,但在上面的示例中,我将它们留空。但是 ExcludeZeroes() 声明似乎不适用于这些字段。

如果我在标准之前手动检查:

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

并为工业做同样的事情,然后标准将起作用。

我假设这与我在 Customer ctor 中初始化 Address 对象有关。我讨厌改变这一点,但我不知道另一种使标准工作的方法,而无需手动检查表单中的空字符串值(从而消除了使用带有 ICriteria 的示例对象的优势)。

为什么?我怎样才能让这个 Criteria 查询工作?

4

2 回答 2

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 ]
    }

}
于 2009-08-19T23:47:37.457 回答
0

我对 QBE 有同样的问题。我还认为 Query by Example 是对对象(和关联)进行通用搜索的一种非常好的方法。已经有 ExcludeNones/Nulls/Zeros。也应该有一个排除空字符串(“”)的选项。

于 2009-07-14T21:18:43.243 回答