我正在为我的ASP.NET MVC应用程序构建一个高级搜索表单。
我有一个Customer对象,带有一个地址组件: 流畅的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 Model Binder从表单传入):
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
行业和国家是网络形式的下拉,但在上面的例子中,我把它们留空了。但ExcludeZeroes()声明似乎不适用于那些字段。
如果我在标准之前手动检查:
if (customer.Address.State == "")
{
customer.Address.State = null;
}
并为行业做同样的事情,然后标准将起作用。
我假设这与我在Customer ctor中初始化Address对象有关。我不想改变这种情况,但我不知道另一种使Criteria工作的方法,而无需手动检查表单中的空字符串值(从而消除了使用带有ICriteria的Example对象的优势)。
为什么呢?如何使此Criteria查询生效?
答案 0 :(得分:1)
使用属性选择器忽略空字符串或空字符串。
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 ]
}
}
答案 1 :(得分:0)
我和QBE有同样的问题。我还认为Query by Example对于对象(和关联)的通用搜索是一种非常好的方法。已经有ExcludeNones / Nulls / Zeros。应该有一个选项来排除空字符串(“”)。