[ActiveRecord]
public class Entity : ActiveRecordBase<Entity>
{
private int id;
private string name;
private string entityDesc;
private string internalName;
[PrimaryKey]
public int Id
{
get { return id; }
set { id = value; }
}
[Searchable][Property]
public string Name
{
get { return name; }
set { name = value; }
}
[Searchable(FriendlyName = "Description")][Property]
public string EntityDesc
{
get { return entityDesc; }
set { entityDesc = value; }
}
[Property]
public string InternalName
{
get { return internalName; }
set { internalName = value; }
}
}
The Searchable takes an optional parameter, FriendlyName that allows to specify a localized or other, more user-friendly name. The attribute can be applied to both properties and relations. If applied to a relation attribute (BelongsTo, HasMany, HasAndBelongsToMany etc.) the properties tagged in that type will be added to the search as well. Then there is a SearchMediator, which will create a NHibernate Criteria Query that will check for every search term whether it can be parsed by the datatype of a tagged property and adds it to the query if this is the case. The code below sketches how the query could be created:
public static T[] Search(string text)
{
string[] words = text.Split();
DetachedCriteria criteria = DetachedCriteria.For<T>();
foreach (string word in words)
{
Disjunction group = Expression.Disjunction();
foreach (PropertyInfo info in typeof (T).GetProperties())
{
if (info.GetCustomAttributes(typeof (SearchableAttribute), true).Length > 0)
group.Add(Expression.Like(info.Name, word, MatchMode.Anywhere));
}
criteria.Add(group);
}
return ActiveRecordMediator<T>.FindAll(criteria);
}
This can be extended by many means. Examples include:
- Allowing propertyName:searchTerm to narrow search to a specific property by its name or friendly name.
- Allowing other operators than the colon like price>10.00 or name!Foo
- Add globbing to specify whether exact matches or all matches should be found
- Specify the MatchMode behavior for string properties as part of SearchableAttribute
Using that mechanism, I can add searching to almost any entity similar to validation. What do you think, would such a Search component benefit the Castle Framework?
That is only some thoughts. I didn't start implementing anything yet. However, anyone interested in helping is welcome, of course.
2 comments:
The idea is logical, but, i don't get what is the idea of having to put a searchable attribute?
Do you have a requirement that a search must be made only on some specific properties?
Basically, what I say is that maybe users will want to search through all properties in all cases, and thus that attributed is rendered redundant, we could simply take all castle property and relation attributes and add that to criteria.
Of course, this way we run into problem that if object graph is too deep, the query gets very big. Probably this might be avoided by specifying object graph depth value when constructing search criteria.
The idea is good, but i wonder what are the exact bussiness needs and use cases that drive this functionality
@Darius
Here is the user need:
I have users here looking at a list of 200+ entities of a type. I built in some filters to narrow that down, but in interviews I perceived that they don't want any filter forms, but "simply" searching through a single text field. It turns out that such a search functionality will be needed on 10+ types for my current application, so I need some generic solution.
Attribute Usage:
Even when specifying graph depth, I will have way to many properties to include them all in a generic search. Some of my entities have 20+ properties, if I including only one relation level, I come to 50+. I don't want to put 50 disjunctions in a single query because I fear that it kills my DBMS.
Please do not forget that this functionality is additional to other, specific filters. It is mainly a "type and go" requirement of lazy users.
-Markus
Post a Comment