我正在为我的 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 查询工作?