Ответ 1
Самое лучшее решение - использовать встроенную функцию таблицы в sql и добавить ее в вашу модель.
В Linq нет полнотекстового поиска, и, похоже, не так много сообщений на эту тему, поэтому у меня была игра, и я придумал этот метод для моего класса utlity:
public static IEnumerable<TSource> GenericFullTextSearch<TSource>(string text, MyDataContext context)
{
//Find LINQ Table attribute
object[] info = typeof(TSource).GetCustomAttributes(typeof(System.Data.Linq.Mapping.TableAttribute), true);
//Get table name
String table = (info[0] as System.Data.Linq.Mapping.TableAttribute).Name;
//Full text search on that table
return context.ExecuteQuery<TSource>(String.Concat("SELECT * FROM ", table, " WHERE CONTAINS(*, {0})"), text);
}
И добавил эту оболочку в каждый частичный класс Linq, где есть полный текстовый индекс
public static IEnumerable<Pet> FullTextSearch(string text, MyDataContext context)
{
return (LinqUtilities.GenericFullTextSearch<Pet>(text, context) as IEnumerable<Pet>);
}
Итак, теперь я могу выполнять полнотекстовый поиск с помощью аккуратного материала, такого как
var Pets = Pet.FullTextSearch(helloimatextbox.Text, MyDataContext).Skip(10).Take(10);
Я предполагаю, что в настоящий момент нужен только очень простой поиск. Может ли кто-нибудь улучшить это? Можно ли реализовать как метод расширения и избежать обертки?
Самое лучшее решение - использовать встроенную функцию таблицы в sql и добавить ее в вашу модель.
Я был очень расстроен отсутствием четких примеров... особенно когда есть потенциально большие наборы данных и пейджинг. Итак, вот пример, который, надеюсь, охватывает все, что вам может понадобиться: -)
create function TS_projectResourceSearch
( @KeyStr nvarchar(4000),
@OwnId int,
@SkipN int,
@TakeN int )
returns @srch_rslt table (ProjectResourceId bigint not null, Ranking int not null )
as
begin
declare @TakeLast int
set @TakeLast = @SkipN + @TakeN
set @SkipN = @SkipN + 1
insert into @srch_rslt
select pr.ProjectResourceId, Ranking
from
(
select t.[KEY] as ProjectResourceId, t.[RANK] as Ranking, ROW_NUMBER() over (order by t.[Rank] desc) row_num
from containstable( ProjectResource,(ResourceInfo, ResourceName), @KeyStr )
as t
) as r
join ProjectResource pr on r.ProjectResourceId = pr.ProjectResourceId
where (pr.CreatorPersonId = @OwnId
or pr.ResourceAvailType < 40)
and r.row_num between @SkipN and @TakeLast
order by r.Ranking desc
return
end
go
select * from ts_projectResourceSearch(' "test*" ',1002, 0,1)
Enjoy, Патрик
Меньше приятный метод (принимает ранг в силу), используя CONTAINSTABLE
String pkey = context.Mapping.GetTable(typeof(TSource)).RowType.DataMembers.SingleOrDefault(x => x.IsPrimaryKey).Name;
string query = String.Concat(@"SELECT *
FROM ", table, @" AS FT_TBL INNER JOIN
CONTAINSTABLE(", table, @", *, {0}) AS KEY_TBL
ON FT_TBL.", pkey, @" = KEY_TBL.[KEY]
ORDER BY KEY_TBL.[RANK] DESC");
return context.ExecuteQuery<TSource>(query, text);
Я использую небольшой взлом, используя методы Поставщик Wrapper. У меня есть код С#, который переписывает магическое слово в SQL с поиском FTS для MS SQL (вы можете настроить любой сервер, который вам нравится).
если у вас есть контекстный класс MyEntities, создайте подкласс типа
public class MyEntitiesWithWrappers : MyEntities
{
private IEFTraceListener listener;
public string FullTextPrefix = "-FTSPREFIX-";
public MyEntitiesWithWrappers(): this("name=MyEntities")
{
}
public MyEntitiesWithWrappers(string connectionString)
: base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(connectionString,"EFTracingProvider"))
{
TracingConnection.CommandExecuting += RewriteFullTextQuery;
}
/// <summary>
/// Rewrites query that contains predefined prefix like: where n.NOTETEXT.Contains(Db.FullTextPrefix + text) with SQL server FTS
/// To be removed when EF will support FTS
/// </summary>
/// <param name="o"></param>
/// <param name="args"></param>
public void RewriteFullTextQuery(object o, CommandExecutionEventArgs args)
{
var text = args.Command.CommandText;
for (int i = 0; i < args.Command.Parameters.Count; i++)
{
DbParameter parameter = args.Command.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;
parameter.Size = 4096;
if (value.IndexOf(FullTextPrefix) >= 0)
{
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;
args.Command.CommandText = Regex.Replace(text,
string.Format(@"\(\[(\w*)\].\[(\w*)\]\s*LIKE\s*@{0}\s?(?:ESCAPE '~')\)", parameter.ParameterName),
string.Format(@"contains([$1].[$2], @{0})", parameter.ParameterName));
}
}
}
}
}
И затем используйте его следующим образом:
var fullTextSearch = Db.FullTextPrefix + textToSearch;
var q = Db.Notes.Where(n => !n.Private && n.NoteText.Contains(fullTextSearch));
Вы можете просто сделать что-то вроде этого
var results = (from tags in _dataContext.View_GetDeterminationTags
where tags.TagName.Contains(TagName) ||
SqlMethods.Like(tags.TagName,TagName)
select new DeterminationTags
{
Row = tags.Row,
Record = tags.Record,
TagID = tags.TagID,
TagName = tags.TagName,
DateTagged = tags.DateTagged,
DeterminationID = tags.DeterminationID,
DeterminationMemberID = tags.DeterminationMemberID,
MemberID = tags.MemberID,
TotalTagged = tags.TotalTagged.Value
}).ToList();
Обратите внимание, где TagName.Contains также SQLMethods.Like просто используйте
using System.Data.Linq.SqlClient;
чтобы получить доступ к этим методам SQL.
Я пытался решить точную проблему. Мне нравится писать свою логику SQL в моем LINQtoSQL, но мне нужен способ полнотекстового поиска. прямо сейчас я просто использую SQL-функции, а затем вызываю пользовательские функции, встроенные в запросы linq. не уверен, что это самый эффективный способ. что вы, ребята, думаете?
dswatik - причина для полнотекстового поиска заключается в том, что .contains переводит на
SELECT * FROM MYTABLE WHERE COLUMNNAME LIKE '%TEXT%'
Что игнорирует любые индексы и ужасно на большой таблице.