score:1
i recently had a similar requirement and ended up writing an iqueryable extension specifically for microsoft full text index access, its available here iqueryablefreetextextensions
score:3
the example here http://www.entityframework.info/home/fulltextsearch is not complete solution. you will need to look into understand how the full text search works. imagine you have a search field and the user types 2 words to hit search. the above code will throw an exception. you need to do pre-processing on the search phrase first to pass it to the query by using logical and or or.
for example your search phrase is "blah blah2" then you need to convert this into:
var searchterm = @"\"blah\" and/or \"blah2\" ";
complete solution would be:
value = regex.replace(value, @"\s+", " "); //replace multiplespaces
value = regex.replace(value, @"[^a-za-z0-9 -]", "").trim();//remove non-alphanumeric characters and trim spaces
if (value.any(char.iswhitespace))
{
value = preprocesssearchkey(value);
}
public static string preprocesssearchkey(string searchkey)
{
var splitedkeywords = searchkey.split(null); //split from whitespaces
// string[] adddoublequotes = new string[splitedkeywords.length];
for (int j = 0; j < splitedkeywords.length; j++)
{
splitedkeywords[j] = $"\"{splitedkeywords[j]}\"";
}
return string.join(" and ", splitedkeywords);
}
this methods uses and logic operator. you might pass that as an argument and use the method for both and or or operators.
you must escape none-alphanumeric characters otherwise it would throw exception when a user enters alpha numeric characters and you have no server site model level validation in place.
score:5
as the other guys mentioned, i would say start using lucene.net
lucene has a pretty high learning curve, but i found an wrapper for it called "simplelucene", that can be found on codeplex
let me quote a couple of codeblocks from the blog to show you how easy it is to use. i've just started to use it, but got the hang of it really fast.
first, get some entities from your repository, or in your case, use entity framework
public class repository
{
public ilist<product> products {
get {
return new list<product> {
new product { id = 1, name = "football" },
new product { id = 2, name = "coffee cup"},
new product { id = 3, name = "nike trainers"},
new product { id = 4, name = "apple ipod nano"},
new product { id = 5, name = "asus eeepc"},
};
}
}
}
the next thing you want to do is create an index-definition
public class productindexdefinition : iindexdefinition<product> {
public document convert(product p) {
var document = new document();
document.add(new field("id", p.id.tostring(), field.store.yes, field.index.not_analyzed));
document.add(new field("name", p.name, field.store.yes, field.index.analyzed));
return document;
}
public term getindex(product p) {
return new term("id", p.id.tostring());
}
}
and create an search index for it.
var writer = new directoryindexwriter(
new directoryinfo(@"c:\index"), true);
var service = new indexservice();
service.indexentities(writer, repository().products, productindexdefinition());
so, you now have an search-able index. the only remaining thing to do is.., searching! you can do pretty amazing things, but it can be as easy as this: (for greater examples see the blog or the documentation on codeplex)
var searcher = new directoryindexsearcher(
new directoryinfo(@"c:\index"), true);
var query = new termquery(new term("name", "football"));
var searchservice = new searchservice();
func<document, productsearchresult> converter = (doc) => {
return new productsearchresult {
id = int.parse(doc.getvalues("id")[0]),
name = doc.getvalues("name")[0]
};
};
ilist<product> results = searchservice.searchindex(searcher, query, converter);
score:19
i have found that the easiest way to implement this is to setup and configure full-text-search in sql server and then use a stored procedure. pass your arguments to sql, allow the db to do its job and return either a complex object or map the results to an entity. you don't necessarily have to have dynamic sql, but it may be optimal. for example, if you need paging, you could pass in pagenumber and pagesize on every request without the need for dynamic sql. however, if the number of arguments fluctuates per query, it will be the optimal solution.
score:54
using interceptors introduced in ef6, you could mark the full text search in linq and then replace it in dbcommand as described in http://www.entityframework.info/home/fulltextsearch:
public class ftsinterceptor : idbcommandinterceptor
{
private const string fulltextprefix = "-ftsprefix-";
public static string fts(string search)
{
return string.format("({0}{1})", fulltextprefix, search);
}
public void nonqueryexecuting(dbcommand command, dbcommandinterceptioncontext<int> interceptioncontext)
{
}
public void nonqueryexecuted(dbcommand command, dbcommandinterceptioncontext<int> interceptioncontext)
{
}
public void readerexecuting(dbcommand command, dbcommandinterceptioncontext<dbdatareader> interceptioncontext)
{
rewritefulltextquery(command);
}
public void readerexecuted(dbcommand command, dbcommandinterceptioncontext<dbdatareader> interceptioncontext)
{
}
public void scalarexecuting(dbcommand command, dbcommandinterceptioncontext<object> interceptioncontext)
{
rewritefulltextquery(command);
}
public void scalarexecuted(dbcommand command, dbcommandinterceptioncontext<object> interceptioncontext)
{
}
public static void rewritefulltextquery(dbcommand cmd)
{
string text = cmd.commandtext;
for (int i = 0; i < cmd.parameters.count; i++)
{
dbparameter parameter = cmd.parameters[i];
if (parameter.dbtype.in(dbtype.string, dbtype.ansistring, dbtype.stringfixedlength, dbtype.ansistringfixedlength))
{
if (parameter.value == dbnull.value)
continue;
var value = (string)parameter.value;
if (value.indexof(fulltextprefix) >= 0)
{
parameter.size = 4096;
parameter.dbtype = dbtype.ansistringfixedlength;
value = value.replace(fulltextprefix, ""); // remove prefix we added n linq query
value = value.substring(1, value.length - 2);
// remove %% escaping by linq translator from string.contains to sql like
parameter.value = value;
cmd.commandtext = regex.replace(text,
string.format(
@"\[(\w*)\].\[(\w*)\]\s*like\s*@{0}\s?(?:escape n?'~')",
parameter.parametername),
string.format(@"contains([$1].[$2], @{0})",
parameter.parametername));
if (text == cmd.commandtext)
throw new exception("fts was not replaced on: " + text);
text = cmd.commandtext;
}
}
}
}
}
static class languageextensions
{
public static bool in<t>(this t source, params t[] list)
{
return (list as ilist<t>).contains(source);
}
}
for example, if you have class note with fts-indexed field notetext:
public class note
{
public int noteid { get; set; }
public string notetext { get; set; }
}
and ef map for it
public class notemap : entitytypeconfiguration<note>
{
public notemap()
{
// primary key
haskey(t => t.noteid);
}
}
and context for it:
public class mycontext : dbcontext
{
static mycontext()
{
dbinterception.add(new ftsinterceptor());
}
public mycontext(string nameorconnectionstring) : base(nameorconnectionstring)
{
}
public dbset<note> notes { get; set; }
protected override void onmodelcreating(dbmodelbuilder modelbuilder)
{
modelbuilder.configurations.add(new notemap());
}
}
you can have quite simple syntax to fts query:
class program
{
static void main(string[] args)
{
var s = ftsinterceptor.fts("john");
using (var db = new mycontext("connstring"))
{
var q = db.notes.where(n => n.notetext.contains(s));
var result = q.take(10).tolist();
}
}
}
that will generate sql like
exec sp_executesql n'select top (10)
[extent1].[noteid] as [noteid],
[extent1].[notetext] as [notetext]
from [ns].[notes] as [extent1]
where contains([extent1].[notetext], @p__linq__0)',n'@p__linq__0 char(4096)',@p__linq__0='(john)
please notice that you should use local variable and cannot move fts wrapper inside expression like
var q = db.notes.where(n => n.notetext.contains(ftsinterceptor.fts("john")));
Source: stackoverflow.com
Related Query
- Entity Framework, Code First and Full Text Search
- SQL subquery result in LINQ and Entity Framework Code First
- Entity Framework Code First override onModelCreating() for TPT Inheritance Screwing Up Identity User and Role Models
- How to support full text search using entity framwork and UnitOfWork and Repository pattern
- Entity Framework 6 Code First Custom Functions
- Entity Framework and Case Insensitive String Search
- Entity Framework Code First without app.config
- Entity Framework Code First using context in Controller
- many to many mapping in entity framework code first
- How to Create a Run-Time Computed (NotMapped) Value in Entity Framework Code First
- Search From database and sort using Entity Framework
- updating data in many-to-many relationship in entity framework in code first existing database
- Entity Framework Code First String Comparison with Oracle Db
- most efficient Entity Framework Code First method of flattening / projecting parent entity with specific child
- Entity Framework Code First - Get blog posts which have certain tags
- How to Query Icollections of Entity Framework Code First Data
- Entity Framework - Linq : how query to take 2 first ordered and grouped list
- Entity Framework code first - Many to Many - Include conditional
- Entity Framework Code First ToList method timing out on SQL Azure
- How to make a property unique in Entity Framework Code First
- How to loop through a child list of objects in Entity Framework 4.1 code first
- how to select data by linq in many-to-many relationship in First code Entity framework 5
- Why Entity Framework Code First one to many Doesn't work properly
- LINQ - Entity framework code first - Grouped results to custom class
- map one to one with multiple primary key columns entity framework code first
- Does Linq in Entity Framework code first use SQL or does it get the whole table first?
- How to get first row from DB using Entity Framework where column starts with certain string and continues with numeric characters
- Fixing Loop Reference in Entity Framework Code First when Serializing to Json
- IQueryable two tables from Code First Entity Framework
- Entity Framework Code First Select Item Based on Relationship
More Query from same tag
- How to Loop through Datatable in Linq?
- Linq select from database table where matching property from List
- How to add another single anonymous type to LINQ query?
- Distinct on a specific field
- Like doesn't escape special characters NHibernate
- How can I use this extension method in a linq to entities query using query syntax?
- Is it possible to remove columns in select query
- Calling a Method inside LINQ
- SQL related , Get latest related record
- Error on System.Linq.Enumerable.<TakeIterator>d__3a`1.MoveNext()
- dynamically build select clause linq
- Aggregate, sum and product of tuples in List
- LINQ to return empty result
- Pass generic EquaityComparer with SequenceEqual
- How to prevent multiple users to update a record at the same time using LINQ
- Quickest way to find the complement of two collections in C#
- LINQ dynamic query with Where clause
- Compare two Lists using LINQ
- Finding all matches in a string
- Add text to all properties in all items of a list without manual multiple loops
- linq-to-entities join 3 tables and group-by statement
- create XML file for each record of the DataTable using Linq C#
- Entity Framework Query - Get Objects in Specific Order
- Merge two Lists in C# and merge objects with the same id into one list item
- LINQ - Contains with anonymous type
- Using Group by with x amount of elements
- Entity Framework Code First using context in Controller
- C# failing to set property inside IEnumerable
- LEFT JOIN in LINQ to entities?
- Structuring two conditional left outer joins into one query using LINQ, C#