Ignore accents on search using linq to entities (EF) and Oracle 12.1 - oracle

I need to perform a search on a table whith a string field that contains accents, many operators could be applied: start with, contains, equal, in the list ...
If I do a search for Müller I want retrieve also Mueller (ue is the translate of ü in German), the same for the other letters having accents, I know that it is possible to achieve this by modifiying the NLS_COMP and NLS_SORT
SQL> ALTER SESSION SET NLS_COMP=LINGUISTIC;
SQL> ALTER SESSION SET NLS_SORT=BINARY_AI;
I know also that it is possible to Collation at column level but this is availble only since 12.2 version,
Any idea please ?
Thank you for your help,
Bilel

I've used oracle NLS session parameters to resolve my issue.
if(condition == true)
AlterSortSession(context);
public void AlterSortSession(MyContext context)
{
var connection = (OracleConnection)context.Database.Connection;
connection.StateChange += AlterSortSession;
}
private static void AlterSortSession(object sender, StateChangeEventArgs e)
{
if (e.CurrentState != ConnectionState.Open)
return;
var connection = (OracleConnection)sender;
OracleGlobalization info = connection.GetSessionInfo();
info.Sort = "XGERMAN_DIN_AI";
info.Comparison = "LINGUISTIC";
connection.SetSessionInfo(info);
}
Documentation is available here for OracleGlobalization

This worked for me for EF4:
using (var context = new Entities()) {
// Set Case Insensitive, Accent Insensitive
var orcl = (OracleConnection)(((System.Data.EntityClient.EntityConnection)(context.Connection)).StoreConnection);
if (context.Connection.State != System.Data.ConnectionState.Open)
{
context.Connection.Open();
}
var sInfo = orcl.GetSessionInfo();
sInfo.Sort = "GENERIC_M_AI";
sInfo.Comparison = "LINGUISTIC";
orcl.SetSessionInfo(sInfo);
// Execute linq query
var row = context.table.Where(a => a.varcharField.Contains("match str")).FirstOrDefault();
}

Related

Explicit construction of entity type in query is not allowed [duplicate]

Using Linq commands and Linq To SQL datacontext, Im trying to instance an Entity called "Produccion" from my datacontext in this way:
Demo.View.Data.PRODUCCION pocoProduccion =
(
from m in db.MEDICOXPROMOTORs
join a in db.ATENCIONs on m.cmp equals a.cmp
join e in db.EXAMENXATENCIONs on a.numeroatencion equals e.numeroatencion
join c in db.CITAs on e.numerocita equals c.numerocita
where e.codigo == codigoExamenxAtencion
select new Demo.View.Data.PRODUCCION
{
cmp = a.cmp,
bonificacion = comi,
valorventa = precioEstudio,
codigoestudio = lblCodigoEstudio.Content.ToString(),
codigopaciente = Convert.ToInt32(lblCodigoPaciente.Content.ToString()),
codigoproduccion = Convert.ToInt32(lblNroInforme.Content.ToString()),
codigopromotor = m.codigopromotor,
fecha = Convert.ToDateTime(DateTime.Today.ToShortDateString()),
numeroinforme = Convert.ToInt32(lblNroInforme.Content.ToString()),
revisado = false,
codigozona = (c.codigozona.Value == null ? Convert.ToInt32(c.codigozona) : 0),
codigoclinica = Convert.ToInt32(c.codigoclinica),
codigoclase = e.codigoclase,
}
).FirstOrDefault();
While executing the above code, I'm getting the following error that the stack trace is included:
System.NotSupportedException was caught
Message="The explicit construction of the entity type 'Demo.View.Data.PRODUCCION' in a query is not allowed."
Source="System.Data.Linq"
StackTrace:
en System.Data.Linq.SqlClient.QueryConverter.VisitMemberInit(MemberInitExpression init)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.VisitSelect(Expression sequence, LambdaExpression selector)
en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.VisitFirst(Expression sequence, LambdaExpression lambda, Boolean isFirst)
en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(Expression node)
en System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
en System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
en System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression)
en System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
en Demo.View.InformeMedico.realizarProduccionInforme(Int32 codigoExamenxAtencion, Double precioEstudio, Int32 comi) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 602
en Demo.View.InformeMedico.UpdateEstadoEstudio(Int32 codigo, Char state) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 591
en Demo.View.InformeMedico.btnGuardar_Click(Object sender, RoutedEventArgs e) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 683
InnerException:
Is that now allowed in LINQ2SQL?
Entities can be created outside of queries and inserted into the data store using a DataContext. You can then retrieve them using queries. However, you can't create entities as part of a query.
I am finding this limitation to be very annoying, and going against the common trend of not using SELECT * in queries.
Still with c# anonymous types there is a workaround, by fetching the objects into an anonymous type, and then copy it over into the correct type.
For example:
var q = from emp in employees where emp.ID !=0
select new {Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
var r = q.ToList();
List<User> users = new List<User>(r.Select(new User
{
Name = r.Name,
EmployeeId = r.EmployeeId
}));
And in the case when we deal with a single value (as in the situation described in the question) it is even easier, and we just need to copy directly the values:
var q = from emp in employees where emp.ID !=0
select new { Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
var r = q.FirstOrDefault();
User user = new User { Name = r.Name, EmployeeId = r.ID };
If the name of the properties match the database columns we can do it even simpler in the query, by doing select
var q = from emp in employees where emp.ID !=0
select new { emp.First, emp.Last, emp.ID }
One might go ahead and write a lambda expression that can copy automatically based on the property name, without needing to specify the values explictly.
Here's another workaround:
Make a class that derives from your LINQ to SQL class. I'm assuming that the L2S class that you want to return is Order:
internal class OrderView : Order { }
Now write the query this way:
var query = from o in db.Order
select new OrderView // instead of Order
{
OrderID = o.OrderID,
OrderDate = o.OrderDate,
// etc.
};
Cast the result back into Order, like this:
return query.Cast<Order>().ToList(); // or .FirstOrDefault()
(or use something more sensible, like BLToolkit / LINQ to DB)
Note: I haven't tested to see if tracking works or not; it works to retrieve data, which is what I needed.
I have found that if you do a .ToList() on the query before trying to contruct new objects it works
I just ran into the same issue.
I found a very easy solution.
var a = att as Attachment;
Func<Culture, AttachmentCulture> make =
c => new AttachmentCulture { Culture = c };
var culs = from c in dc.Cultures
let ac = c.AttachmentCultures.SingleOrDefault(
x => x.Attachment == a)
select ac == null ? make(c) : ac;
return culs;
I construct an anonymous type, use IEnumerable (which preserves deferred execution), and then re-consruct the datacontext object. Both Employee and Manager are datacontext objects:
var q = dc.Employees.Where(p => p.IsManager == 1)
.Select(p => new { Id = p.Id, Name = p.Name })
.AsEnumerable()
.Select(item => new Manager() { Id = item.Id, Name = item.Name });
Within the book "70-515 Web Applications Development with Microsoft .NET Framework 4 - Self paced training kit", page 638 has the following example to output results to a strongly typed object:
IEnumerable<User> users = from emp in employees where emp.ID !=0
select new User
{
Name = emp.First + " " + emp.Last,
EmployeeId = emp.ID
}
Mark Pecks advice appears to contradict this book - however, for me this example still displays the above error as well, leaving me somewhat confused. Is this linked to version differences? Any suggestions welcome.
I found another workaround for the problem that even lets you retain your result as IQueryale, so it doesn't actually execute the query until you want it to be executed (like it would with the ToList() method).
So linq doesn't allow you to create an entity as a part of query? You can shift that task to the database itself and create a function that will grab the data you want. After you import the function to your data context, you just need to set the result type to the one you want.
I found out about this when I had to write a piece of code that would produce a IQueryable<T> in which the items don't actually exist in the table containing T.
pbz posted a work around by creating a View class inherited from an entity class that you could be working with. I'm working with a dbml model of a table that has > 200 columns. When I try and return the whole table I get "Root Element missing" errors. I couldn't find anyone who wanted to deal with my particular issue so I was looking at rewriting my entire approach. Just creating a view class for the entitiy class worked in my case.
As pbz suggests : Create a view class that inherits from your entity class. For me this is tbCamp so :
internal class tbCampView : tbCamp
{
}
Then use the view class in your query :
using (var dc = ConnectionClass.Connect(Dev))
{
var camps = dc.tbCamps.Select(s => new tbCampView
{
active = s.active,
idCamp = s.idCamp,
campName = s.campName
});
SmartTableViewer(camps, dg1);
}
private void SmartTableViewer<T>(IEnumerable<T> allRecords)
{
// Build sorted rows back into new table
var table = new DataTable();
// Create columns based on type
if (allRecords is IEnumerable<tbCamp> tbCampRecords)
{
// Get the columns you want
table.Columns.Add("idCamp");
table.Columns.Add("campName");
foreach (var record in tbCampRecords)
{
// Make a new row
var r = table.NewRow();
// Add the contents to each column of the row
r["idCamp"] = record.idCamp;
r["campName"] = record.campName;
// Add the row to the table.
table.Rows.Add(r);
}
}
else
{
MessageBox.Show("Unhandled type. Add support for new data type in SmartTableViewer()");
return;
}
// Update table in grid
dg1.DataSource = table.DefaultView;
}
Here is what happens when you try and create an entity class object in the query.
I didn't want to have to use an anonymous type if I could help it because I wanted the type to be tbCamp. Since tbCampView is of type tbCamp the is operator works well. see Brian Hasden's answer Passing a generic List<> in C#
I'm surprised this is even an issue but with larger tables I run into this error so I thought I would just show it here :
When trying to read this table into memory I get the following error. There are < 2000 rows but the columns are > 200 for each. I don't know if that is an issue or not.
If I just want a few columns I need to create a custom class and handle that which isn't that big of a pain. With the approach pbz provided I don't have to worry about it.
Here is the entire project in case it helps someone.
public partial class Form1 : Form
{
private const bool Dev = true;
public Form1()
{
InitializeComponent();
}
private void btnGetAllCamps_Click(object sender, EventArgs e)
{
using (var dc = ConnectionClass.Connect(Dev))
{
IQueryable<tbCampView> camps = dc.tbCamps.Select(s => new tbCampView
{
// Project columns as needed.
active = s.active,
idCamp = s.idCamp,
campName = s.campName
});
// pass in as a
SmartTableViewer(camps);
}
}
private void SmartTableViewer<T>(IEnumerable<T> allRecords)
{
// Build sorted rows back into new table
var table = new DataTable();
// Create columns based on type
if (allRecords is IEnumerable<tbCamp> tbCampRecords)
{
// Get the columns you want
table.Columns.Add("idCamp");
table.Columns.Add("campName");
foreach (var record in tbCampRecords)
{
//var newRecord = record;
// Make a new row
var r = table.NewRow();
// Add the contents to each column of the row
r["idCamp"] = record.idCamp;
r["campName"] = record.campName;
// Add the row to the table.
table.Rows.Add(r);
}
}
else
{
MessageBox.Show("Unhandled type. Add support for new data type in SmartTableViewer()");
return;
}
// Update table in grid
dg1.DataSource = table.DefaultView;
}
internal class tbCampView : tbCamp
{
}
}

linq: Using methods in select clause

I'm breaking my head with this and decided to share my problem with you
I want to create an anonymous select from several tables, some of them may contain more than one result. i want to concatenate these results into one string
i did something like this:
var resultTable = from item in dc.table
select new
{
id= item.id,
name= CreateString((from name in item.Ref_Items_Names
select name.Name).ToList()),
};
and the CreateString() is:
private string CreateString(List<string> list)
{
StringBuilder stringedData = new StringBuilder();
for (int i = 0; i < list.Count; i++)
{
stringedData.Append(list[i] + ", ");
}
return stringedData.ToString();
}
my intentions were to convert the "name" query to list and then sent it to CreateString() to convert it to one long concatenated string.
I tried using .Aggregate((current,next) => current + "," + next);
but when i try to convert my query to DataTable like below:
public DataTable ToDataTable(Object query)
{
DataTable dt = new DataTable();
IDbCommand cmd = dc.GetCommand(query as IQueryable);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = (SqlCommand)cmd;
cmd.Connection.Open();
adapter.Fill(dt);
cmd.Connection.Close();
return dt;
}
I'm getting exception that "dc.GetCommand()" can't understand query with Aggregate method
later I tried to even use this simple query:
var resultTable = from itemin dc.table
select new
{
name = CreateString()
};
When CreateString() returns "success", nothing was inserted to "name"
why there is no way of using methods in select clause?
Thank you
Yotam
There is difference between LINQ to objects and LINQ to some-db-provider. Generally speaking, when using IQueryable, you can't use any methods, except the ones your provider understands.
What you can do is to retrieve the data from the database and then do the formatting using LINQ to objects:
var data = from item in dc.table
where /* some condition */
select item;
var result = from item in data.AsEnumerable()
select new
{
name = SomeFunction(item)
}
The AsEnumerable() extension method forces processing using LINQ to objects.
Forgive me if I've miss interpreted your question. It seems that what you are trying to do is abstract your select method for reuse. If this is the case, you may consider projection using a lambda expression. For example:
internal static class MyProjectors
{
internal static Expression<Func<Object1, ReturnObject>> StringDataProjector
{
get
{
return d => new Object1()
{
//assignment here
}
}
}
}
Now you can select your datasets as such:
dc.Table.Select(MyProjectors.StringDataProjector)
As for the concatenation logic, what about selecting to some base class with an IEnumerable<string> property and a read-only property to handle the concatenation of the string?

NHibernate LINQ 3.0 Oracle Expression type 10005 is not supported by this SelectClauseVisitor

I have the following LINQ query
QueryResult<List<PersonDemographic>> members = new QueryResult<List<PersonDemographic>>();
var query = (from ms in this.Session.Query<MemberSummary>()
where ms.NameSearch.StartsWith(firstName.ToUpper())
&& ms.NameSearch2.StartsWith(lastName.ToUpper())
select new PersonDemographic
{
FirstName = ms.FirstName.ToProperCase(),
LastName = ms.LastName.ToProperCase(),
PersonId = ms.Id,
Address = new Address
{
Line1 = ms.AddressLine1.ToProperCase(),
Line2 = ms.AddressLine2.ToProperCase(),
City = ms.City.ToProperCase(),
State = ms.State,
Zipcode = ms.Zipcode,
},
PhoneNumber = new PhoneNumber
{
Number = string.IsNullOrWhiteSpace(ms.PhoneNumber) ? null : Regex.Replace(ms.PhoneNumber, #"(\d{3})(\d{3})(\d{4})", "$1-$2-$3")
}
});
if (this.Session.Transaction.IsActive)
{
members.Data = query.Distinct().Take(15).ToList();
}
else
{
using (var transaction = this.Session.BeginTransaction())
{
members.Data = query.Distinct().Take(15).ToList();
transaction.Commit();
}
}
The code is running under the transaction section. If I use it without a Distinct I have no problem. Adding the Distinct gives me an exception
{"Expression type 10005 is not supported by this SelectClauseVisitor."}
I can't find anything definitive. Can anyone help?
Thanks,
Paul
There are lots of things in that query that NH can't possibly know how to translate to SQL:
ToProperCase (that looks like an extension method of yours)
string.IsNullOrWhiteSpace (that's new in .NET 4, NH is compiled against 3.5)
Regex.Replace (that's just not possible to do with SQL, unless you have a DB that supports it and write a Dialect for it)

ODP.NET and parameters

I have built a common app that works with PostgreSQL and should work on Oracle.
However i'm getting strange errors when inserting records through a parametrized query.
My formatted query looks like this:
"INSERT INTO layer_mapping VALUES (#lm_id,#lm_layer_name,#lm_layer_file);"
Unlike Npgsql which documents how to use the parameters, i could not found how Oracle "prefers" them to be used. I could only find :1, :2, :3, for example.
I do not wanto use sequential parameters, i want to use them in a named way.
Is there a way to do it? Am i doing something wrong?
Thanks
You can use named parameters with ODP.NET like so:
using (var cx=new OracleConnection(connString)){
using(var cmd=cx.CreateCommand()){
cmd.CommandText="Select * from foo_table where bar=:bar";
cmd.BindByName=true;
cmd.Parameters.Add("bar",barValue);
///...
}
}
I made this lib https://github.com/pedro-muniz/ODPNetConnect/blob/master/ODPNetConnect.cs
so you can do parameterized write and read like this:
ODPNetConnect odp = new ODPNetConnect();
if (!String.IsNullOrWhiteSpace(odp.ERROR))
{
throw new Exception(odp.ERROR);
}
//Write:
string sql = #"INSERT INTO TABLE (D1, D2, D3) VALUES (:D1, :D2, :D3)";
Dictionary<string, object> params = new Dictionary<string, object>();
params["D1"] = "D1";
params["D2"] = "D2";
params["D3"] = "D3";
int affectedRows = odp.ParameterizedWrite(sql, params);
if (!String.IsNullOrWhiteSpace(odp.ERROR))
{
throw new Exception(odp.ERROR);
}
//read
string sql = #"SELECT * FROM TABLE WHERE D1 = :D1";
Dictionary<string, object> params = new Dictionary<string, object>();
params["D1"] = "D1";
DataTable dt = odp.ParameterizedRead(sql, params);
if (!String.IsNullOrWhiteSpace(odp.ERROR))
{
throw new Exception(odp.ERROR);
}
Notes: you have to change these lines in ODPNetConnect.cs to set connection string:
static private string devConnectionString = "SET YOUR DEV CONNECTION STRING";
static private string productionConnectionString = "SET YOUR PRODUCTION CONNECTION STRING";
And you need to change line 123 to set environment to dev or prod.
public OracleConnection GetConnection(string env = "dev", bool cacheOn = false)

Full Text Search in Linq

There's no full text search built into Linq and there don't seem to be many posts on the subject so I had a play around and came up with this method for my utlity class:
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);
}
And added this wrapper to each partial Linq class where there is a full text index
public static IEnumerable<Pet> FullTextSearch(string text, MyDataContext context)
{
return (LinqUtilities.GenericFullTextSearch<Pet>(text, context) as IEnumerable<Pet>);
}
So now I can do full text searches with neat stuff like
var Pets = Pet.FullTextSearch(helloimatextbox.Text, MyDataContext).Skip(10).Take(10);
I'm assuming only a very basic search is necessary at present. Can anyone improve on this? Is it possible to implement as an extension method and avoid the wrapper?
The neatest solution is to use an inline table valued function in sql and add it to your model
http://sqlblogcasts.com/blogs/simons/archive/2008/12/18/LINQ-to-SQL---Enabling-Fulltext-searching.aspx
To get it working you need to create a table valued function that does
nothing more than a CONTAINSTABLE query based on the keywords you
pass in,
create function udf_sessionSearch
(#keywords nvarchar(4000)) returns table as return (select [SessionId],[rank]
from containstable(Session,(description,title),#keywords))
You then add this function to your LINQ 2 SQL model and he presto you
can now write queries like.
var sessList = from s in DB.Sessions
join fts in DB.udf_sessionSearch(SearchText) on s.sessionId equals fts.SessionId
select s;
I was pretty frustrated with the lack of clear examples... especially when there are potentially large data sets and paging is needed. So, here's an example that hopefully encompasses everything you might need :-)
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,
Patrick
I use a little hack using Provider Wrapper techniques. I have a c# code that rewrite magic word in SQL with FTS search for MS SQL (you can adjust for any server you like).
if you have context class MyEntities, create subclass like
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));
}
}
}
}
}
And then use it like this:
var fullTextSearch = Db.FullTextPrefix + textToSearch;
var q = Db.Notes.Where(n => !n.Private && n.NoteText.Contains(fullTextSearch));
A slighty nicer method (takes rank into effect) using 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);
.NET Core 2.1 and above supports an extension method that allows the use of FREETEXT and FREETEXTTABLE searches
using Microsoft.EntityFrameworkCore;
var results = dbContext.MyTable
.Where(e => EF.Functions.FreeText("*", "search criteria"));
The FreeText function is defined in Microsoft.EntityFrameworkCore.SqlServer so your project must reference that package.
Documentation
I've been trying to solve the exact problem. I like to write my SQL logic in my LINQtoSQL but I needed a way to do Full Text Search. right now I'm just using SQL functions and then calling the user-defined functions inline of the linq queries. not sure if that's the most efficient way. what do you guys think?
You can just do something like this
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();
Notice where TagName.Contains also the SQLMethods.Like just do a using
using System.Data.Linq.SqlClient;
to gain access to that SQLMethods.
dswatik - the reason for wanting full text search is that .contains translates to
SELECT * FROM MYTABLE WHERE COLUMNNAME LIKE '%TEXT%'
Which ignores any indexes and is horrible on a large table.

Resources