什么是Lucene.net?
引用wikipedia上的介绍:“Lucene是一套用于全文检索和搜尋的開放源碼程式庫,由Apache软件基金会支持和提供。Lucene提供了一個簡單卻強大的應用程式介面,能夠做全文索引和搜尋...”
而Lucene.net便是Lucene在dot net平台上的移植版本。关于Lucene的一些概念,有兴趣的朋友可以参考这里。
要实现Spring.net与Lucene.net的整合,关键点在于:
1、查询时,使用Spring.net集成的nHibernate来管理Lucene.net使用的Session;
2、对数据实体的CRUD进行事件监控,以便动态更新索引
经过一番尝试,决定将原有的框架进行升级——spring.net 1.2.0 + nHibernaet 2.0.1 + Lucene.net 2.0 + nHibernate.Search。
ok,看看都需要进行哪些调整:
一、实体生成模板加上索引
在model层引用nHibernate.Search程序集,它的作用是根据实体上的元标记,选择是否为实体开启存储空间,以及索引的字段范围。
修改codeSmith中的nHibernate Template,像这样,用以将主键和字符型字段进行索引:
<%&#64; CodeTemplate Language&#61;"C#" TargetLanguage&#61;"C#" Description&#61;"Generates a C# class for use with NHibnate" %>
<%&#64; Property Name&#61;"SourceTable" Type&#61;"SchemaExplorer.TableSchema" Category&#61;"Context" Description&#61;"Table that the mapping file is based on" %>
<%&#64; Property Name&#61;"Namespace" Type&#61;"System.String" Default&#61;"MyNamespace.Data" Category&#61;"Object" Description&#61;"The class namespace that the mapping file should use" %>
<%&#64; Property Name&#61;"Assembly" Type&#61;"System.String" Default&#61;"MyApp.MyAssembly" Category&#61;"Object" Description&#61;"The assembly that the class will be used in" %>
<%&#64; Property Name&#61;"RemoveTablePrefix" Type&#61;"System.String" Default&#61;"tbl" Category&#61;"Object" Description&#61;"The prefix to remove from table names" %>
<%&#64; Property Name&#61;"ForceId" Type&#61;"System.Boolean" Default&#61;"true" Category&#61;"Object" Description&#61;"Force Id for identity column" %>
<%&#64; Assembly Name&#61;"SchemaExplorer" %>
<%&#64; Assembly Name&#61;"System.Data" %>
<%&#64; Import Namespace&#61;"SchemaExplorer" %>
<%&#64; Import Namespace&#61;"System.Data" %>
<%&#64; Import Namespace&#61;"System.Text.RegularExpressions" %>
using System;
using System.Collections.Generic;
using NHibernate.Search.Attributes;
using NHibernate.Search;
namespace <%&#61; Namespace %>
{
#region <%&#61; ClassName(SourceTable) %>
///
/// <%&#61; ClassName(SourceTable) %> object for NHibernate mapped table &#39;<%&#61; ClassTable(SourceTable) %>&#39;.
///
[Serializable]
[TableInfo(TableName &#61; "<%&#61; ClassTable(SourceTable) %>", PrimaryKey &#61; "<%&#61; ColumnName(SourceTable.PrimaryKey.MemberColumns[0])%>" , Columns&#61;"<% for(int i&#61;0;i
[Indexed(Index &#61; "<%&#61; ClassName(SourceTable) %>")]
public class <%&#61; ClassName(SourceTable) %>
{
#region Member Variables
<% if (SourceTable.PrimaryKey.MemberColumns.Count &#61;&#61; 1) {%>
protected <%&#61; IdMemberType(SourceTable) %> <%&#61; IdMemberName(SourceTable) %>;
<% } %>
<% foreach(ColumnSchema column in SourceTable.NonKeyColumns) { %>
protected <%&#61; MemberType(column) %> <%&#61; MemberName(column) %>;
<% } %>
<% foreach (TableKeySchema foreignKey in SourceTable.ForeignKeys) { %>
protected <%&#61; ManyToOneClass(foreignKey) %> <%&#61; ManyToOneMemberName(foreignKey) %>;
<% if ((foreignKey.ForeignKeyTable &#61;&#61; SourceTable) && (foreignKey.PrimaryKeyTable &#61;&#61; SourceTable)) { %>
protected <%&#61; CollectionType(foreignKey)%> <%&#61; CollectionMemberName(foreignKey)%>;
<% } %>
<% } %>
<% foreach(TableKeySchema primaryKey in SourceTable.PrimaryKeys) { %>
<% if (IsManyToManyTable(primaryKey.ForeignKeyTable)) { %>
protected <%&#61; CollectionType(primaryKey)%> <%&#61; CollectionManyToManyMemberName(primaryKey)%>;
<% } else if (IsOneToOneTable(primaryKey)) { %>
protected <%&#61; OneToOneClass(primaryKey) %> <%&#61; OneToOneMemberName(primaryKey) %>;
<% } else if (IsSubClassTable(primaryKey)) { %>
<% } else { %>
protected <%&#61; CollectionType(primaryKey)%> <%&#61; CollectionMemberName(primaryKey)%>;
<% } %>
<% } %>
#endregion
#region Constructors
public <%&#61; ClassName(SourceTable) %>() { }
public <%&#61; ClassName(SourceTable) %>( <%
int count &#61; 0;
foreach(ColumnSchema column in SourceTable.NonKeyColumns)
{
if (count > 0) Response.Write(", ");
%><%&#61; MemberType(column) %> <%&#61; ParameterName(column) %><%
count &#43;&#43;;
}
foreach(TableKeySchema foreignKey in SourceTable.ForeignKeys)
{
if (count > 0) Response.Write(", ");
%><%&#61; ManyToOneClass(foreignKey) %> <%&#61; ManyToOneParameterName(foreignKey) %><%
count &#43;&#43;;
}
%> )
{
<% foreach(ColumnSchema column in SourceTable.NonKeyColumns) { %>
this.<%&#61; MemberName(column) %> &#61; <%&#61; ParameterName(column) %>;
<% } %>
<% foreach(TableKeySchema foreignKey in SourceTable.ForeignKeys) { %>
this.<%&#61; ManyToOneMemberName(foreignKey) %> &#61; <%&#61; ManyToOneParameterName(foreignKey) %>;
<% } %>
}
#endregion
#region Public Properties
<% if (SourceTable.PrimaryKey.MemberColumns.Count &#61;&#61; 1) {%>
[DocumentId]
public <%&#61; IdMemberType(SourceTable) %> <%&#61; IdName(SourceTable) %>
{
get {return <%&#61; IdMemberName(SourceTable) %>;}
<% if (IdMemberType(SourceTable) &#61;&#61; "string" ) {%>
set
{
if ( value !&#61; null && value.Length > <%&#61; ColumnLength(SourceTable.PrimaryKey.MemberColumns[0])%>)
throw new ArgumentOutOfRangeException("Invalid value for <%&#61; IdName(SourceTable) %>", value, value.ToString());
<%&#61; IdMemberName(SourceTable) %> &#61; value;
}
<% } else { %>
set {<%&#61; IdMemberName(SourceTable) %> &#61; value;}
<% } %>
}
<% } %>
<% foreach(ColumnSchema column in SourceTable.NonKeyColumns) { %>
<%if( MemberType(column) &#61;&#61;"string"){%>
[Field(Index.Tokenized, Store &#61; Store.Yes)]
<%}%>
public <%&#61; MemberType(column) %> <%&#61; PropertyName(column) %>
{
get { return <%&#61; MemberName(column) %>; }
<% if (MemberType(column) &#61;&#61; "string") {%>
set
{
<% if(ColumnLength(column) !&#61; "16" ){ %>
if ( value !&#61; null && value.Length > <%&#61; ColumnLength(column)%>)
throw new ArgumentOutOfRangeException("Invalid value for <%&#61; PropertyName(column) %>", value, value.ToString());
<%}%>
<%&#61; MemberName(column) %> &#61; value;
}
<% } else { %>
set { <%&#61; MemberName(column) %> &#61; value; }
<% } %>
}
<% } %>
<% foreach(TableKeySchema foreignKey in SourceTable.ForeignKeys) { %>
public <%&#61; ManyToOneClass(foreignKey) %> <%&#61; ManyToOneName(foreignKey) %>
{
get { return <%&#61; ManyToOneMemberName(foreignKey) %>; }
set { <%&#61; ManyToOneMemberName(foreignKey) %> &#61; value; }
}
<% if ((foreignKey.ForeignKeyTable &#61;&#61; SourceTable) && (foreignKey.PrimaryKeyTable &#61;&#61; SourceTable)) { %>
public <%&#61; CollectionType(foreignKey) %> <%&#61; CollectionName(foreignKey) %>
{
get { return <%&#61; CollectionMemberName(foreignKey) %>; }
set { <%&#61; CollectionMemberName(foreignKey) %> &#61; value; }
}
<% } %>
<% } %>
<% foreach(TableKeySchema primaryKey in SourceTable.PrimaryKeys) { %>
<% if (IsManyToManyTable(primaryKey.ForeignKeyTable)) { %>
public <%&#61; CollectionType(primaryKey) %> <%&#61; CollectionManyToManyName(primaryKey) %>
{
get
{
if (<%&#61; CollectionManyToManyMemberName(primaryKey) %>&#61;&#61;null)
{
<%&#61; CollectionManyToManyMemberName(primaryKey) %> &#61; <%&#61; NewCollectionType(primaryKey) %>;
}
return <%&#61; CollectionManyToManyMemberName(primaryKey) %>;
}
set { <%&#61; CollectionManyToManyMemberName(primaryKey) %> &#61; value; }
}
<% } else if (IsOneToOneTable(primaryKey)) { %>
public <%&#61; OneToOneClass(primaryKey) %> <%&#61; OneToOneName(primaryKey) %>
{
get { return <%&#61; OneToOneMemberName(primaryKey) %>; }
set { <%&#61; OneToOneMemberName(primaryKey) %> &#61; value; }
}
<% } else if (IsSubClassTable(primaryKey)) { %>
<% } else { %>
public <%&#61; CollectionType(primaryKey) %> <%&#61; CollectionName(primaryKey) %>
{
get
{
if (<%&#61; CollectionMemberName(primaryKey) %>&#61;&#61;null)
{
<%&#61; CollectionMemberName(primaryKey) %> &#61; <%&#61; NewCollectionType(primaryKey) %>;
}
return <%&#61; CollectionMemberName(primaryKey) %>;
}
set { <%&#61; CollectionMemberName(primaryKey) %> &#61; value; }
}
<% } %>
<% } %>
#endregion
<% foreach(TableKeySchema primaryKey in SourceTable.PrimaryKeys) { %>
<% if (IsManyToManyTable(primaryKey.ForeignKeyTable)) { } %>
<% else if (IsSubClassTable(primaryKey)) { %>
#region <%&#61; JoinedSubclassName(primaryKey) %>
///
/// <%&#61; JoinedSubclassName(primaryKey) %> object for NHibernate mapped table &#39;<%&#61; JoinedSubclassTable(primaryKey) %>&#39;.
///
public class <%&#61; JoinedSubclassName(primaryKey) %> : <%&#61; ClassName(SourceTable) %>
{
#region Member Variables
<% foreach(ColumnSchema column in primaryKey.ForeignKeyTable.NonKeyColumns) { %>
protected <%&#61; MemberType(column) %> <%&#61; MemberName(column) %>;
<% } %>
<% foreach (TableKeySchema foreignKey in primaryKey.ForeignKeyTable.ForeignKeys) { %>
<% if (foreignKey.PrimaryKeyTable !&#61; SourceTable) { %>
protected <%&#61; ManyToOneClass(foreignKey) %> <%&#61; ManyToOneMemberName(foreignKey) %>;
<% } %>
<% if ((foreignKey.ForeignKeyTable &#61;&#61; primaryKey.ForeignKeyTable) && (foreignKey.PrimaryKeyTable &#61;&#61; primaryKey.ForeignKeyTable)) { %>
protected <%&#61; CollectionType(foreignKey)%> <%&#61; CollectionMemberName(foreignKey)%>;
<% } %>
<% } %>
#endregion
#region Constructors
public <%&#61; JoinedSubclassName(primaryKey) %>() : base() { }
public <%&#61; JoinedSubclassName(primaryKey) %>( <%
count &#61; 0;
foreach(ColumnSchema column in SourceTable.NonKeyColumns)
{
if (count > 0) Response.Write(", ");
%><%&#61; MemberType(column) %> <%&#61; ParameterName(column) %><%
count &#43;&#43;;
}
foreach(TableKeySchema foreignKey in SourceTable.ForeignKeys)
{
if (count > 0) Response.Write(", ");
%><%&#61; ManyToOneClass(foreignKey) %> <%&#61; ManyToOneParameterName(foreignKey) %><%
count &#43;&#43;;
}
foreach(ColumnSchema column in primaryKey.ForeignKeyTable.NonKeyColumns)
{
if (count > 0) Response.Write(", ");
%><%&#61; MemberType(column) %> <%&#61; ParameterName(column) %><%
count &#43;&#43;;
}
foreach(TableKeySchema foreignKey in primaryKey.ForeignKeyTable.ForeignKeys)
{
if (foreignKey.PrimaryKeyTable !&#61; SourceTable)
{
if (count > 0) Response.Write(", ");
%><%&#61; ManyToOneClass(foreignKey) %> <%&#61; ManyToOneParameterName(foreignKey) %><%
count &#43;&#43;;
}
}
%> ) : base(<%
count &#61; 0;
foreach(ColumnSchema column in SourceTable.NonKeyColumns)
{
if (count > 0) Response.Write(", ");
%><%&#61; ParameterName(column) %><%
count &#43;&#43;;
}
foreach(TableKeySchema foreignKey in SourceTable.ForeignKeys)
{
if (count > 0) Response.Write(", ");
%><%&#61; ManyToOneParameterName(foreignKey) %><%
count &#43;&#43;;
}
%>)
{
<% foreach(ColumnSchema column in primaryKey.ForeignKeyTable.NonKeyColumns) { %>
this.<%&#61; MemberName(column) %> &#61; <%&#61; ParameterName(column) %>;
<% } %>
<% foreach (TableKeySchema foreignKey in primaryKey.ForeignKeyTable.ForeignKeys) { %>
<% if (foreignKey.PrimaryKeyTable !&#61; SourceTable) { %>
this.<%&#61; ManyToOneName(foreignKey) %> &#61; <%&#61; ManyToOneParameterName(foreignKey) %>;
<% } %>
<% } %>
}
#endregion
#region Public Properties
<% foreach(ColumnSchema column in primaryKey.ForeignKeyTable.NonKeyColumns) { %>
public <%&#61; MemberType(column) %> <%&#61; PropertyName(column) %>
{
get { return <%&#61; MemberName(column) %>; }
set { <%&#61; MemberName(column) %> &#61; value; }
}
<% } %>
<% foreach(TableKeySchema foreignKey in primaryKey.ForeignKeyTable.ForeignKeys) { %>
<% if (foreignKey.PrimaryKeyTable !&#61; SourceTable) { %>
public <%&#61; ManyToOneClass(foreignKey) %> <%&#61; ManyToOneName(foreignKey) %>
{
get { return <%&#61; ManyToOneMemberName(foreignKey) %>; }
set { <%&#61; ManyToOneMemberName(foreignKey) %> &#61; value; }
}
<% } %>
<% if ((foreignKey.ForeignKeyTable &#61;&#61; primaryKey.ForeignKeyTable) && (foreignKey.PrimaryKeyTable &#61;&#61; primaryKey.ForeignKeyTable)) { %>
public <%&#61; CollectionType(foreignKey) %> <%&#61; CollectionName(foreignKey) %>
{
get { return <%&#61; CollectionName(foreignKey) %>; }
set { <%&#61; CollectionName(foreignKey) %> &#61; value; }
}
<% } %>
<% } %>
#endregion
}
#endregion
<% } %>
<% } %>
}
#endregion
}
在例程包中的“其他”目录中&#xff0c;有完整的生成模板。
二、集成环境配置
修改web.config&#xff0c;进行Spring.net和nHibernate.Search的配置&#xff1a;
此处的"hibernate.search.default.indexBase"值"~/Index"可以更改为您希望的目录名称。这里的意义在于&#xff0c;当监控到数据变化时&#xff0c;会将索引变化写入到"~/Index/实体名/“。
在nHibernate 2.0中&#xff0c;加入了对数据库事件的监控&#xff0c;在配置文件中&#xff0c;给集成环境中的SessionFactory加上"EventListeners" 属性&#xff0c;便可轻松捕捉到诸如Insert、Update、Delete等事件&#xff0c;交由nHibernate.Search进行索引处理&#xff1a;
三、全文搜索
给数据访问模板DaoTemplate添加一个全文搜索的方法&#xff1a;
/// 全文检索
///
///
/// 关键词
///
IList FullTextSearch(string query)
四、运行一下
Insert对象&#xff1a;
Search&#xff1a;