Importing SQL Server's CONTAINS() as a model defined function - sql-server

I am trying to import SQL Server's CONTAINS() function in my Entity Framework model so that I can use it in my LINQ queries.
I have added this to my EDM:
<Function Name="FullTextSearch" ReturnType="Edm.Boolean">
<Parameter Name="Filter" Type="Edm.String" />
<DefiningExpression>
CONTAINS(*, Filter)
</DefiningExpression>
</Function>
Add created my method stub:
[EdmFunction("MyModelNamespace", "FullTextSearch")]
public static bool FullTextSearch(string filter)
{
throw new NotSupportedException("This function is only for L2E query.");
}
I try to call the function like this:
from product in Products
where MyModel.FullTextSearch("FORMSOF(INFLECTIONAL, robe)")
select product
The following exception is raised:
The query syntax is not valid. Near term '*'
I realize that the function I defined is not directly linked to the entity set being queried so that could also be a problem.
Is there any way to pull this off?

The function you have defined above uses Entity SQL, not Transact SQL, so I think the first step is to figure out whether CONTAINS(*,'text') can be expressed in Entity SQL.
Entity SQL doesn't support the * operator as described here: http://msdn.microsoft.com/en-us/library/bb738573.aspx and if I try
entities.CreateQuery<TABLE_NAME>("select value t from TABLE_NAME as t where CONTAINS(*, 'text')");
I get the same error you got above. If I try to explicitly pass the column it works:
entities.CreateQuery<TABLE_NAME>("select value t from TABLE_NAME as t where CONTAINS(t.COLUMN_NAME, 'text')");
But when I look at the SQL it translated it to a LIKE expression.
ADO.NET:Execute Reader "SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[TABLE_NAME] AS [Extent1]
WHERE (CASE WHEN ([Extent1].[COLUMN_NAME] LIKE '%text%') THEN cast(1 as bit) WHEN ( NOT ([Extent1].[COLUMN_NAME] LIKE '%text%')) THEN cast(0 as bit) END) = 1
) AS [GroupBy1]"
If you cannot express the query using Entity SQL you'll have to use a Stored Procedure or other mechanism to use Transact SQL directly.

This is way beyond me but could you try
from product in Products where MyModel.FullTextSearch(product, "FORMSOF(INFLECTIONAL, robe)") select product
My reasoning is that in SQL Server it is expecting two parameters.

I inserted a little function into my code, in a class which inherits from the Context class, which points to my SQL function supporting Full Text searching, my solution is a little more closed ended to yours (not allowing the specification of the type of text search), it returns an IEnumerable, essentially a list of primary keys matching the searching criteria, something like this;
public class myContext : DataContext
{
protected class series_identity
{
public int seriesID;
series_identity() { }
};
[Function(Name = "dbo.fnSeriesFreeTextSearchInflectional", IsComposable = true)]
protected IQueryable<series_identity> SynopsisSearch([Parameter(DbType = "NVarChar")] string value)
{
return this.CreateMethodCallQuery<series_identity>(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), value);
}
public IEnumerable<int> Search(string value)
{
var a = from t1 in SynopsisSearch(value)
select t1.seriesID;
return a;
}
};
usage is something like;
myContext context = new myContext();
IEnumerable<int> series_identities = (from t1 in context.Search("some term")
select t1).Distinct();

Related

How do I use SQL LIKE '%value%' operator with Azure Functions SQL Binding?

With the Preview version of the Azure Function SQL Input Binding, you can easily execute SQL queries by specifying it in the binding, e.g.:
[FunctionName("GetToDoItem")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "gettodoitem")]
HttpRequest req,
[Sql("select [Id], [order], [title], [url], [completed] from dbo.ToDo where Id = #Id",
CommandType = System.Data.CommandType.Text,
Parameters = "#Id={Query.id}",
ConnectionStringSetting = "SqlConnectionString")]
IEnumerable<ToDoItem> toDoItem)
{
return new OkObjectResult(toDoItem.FirstOrDefault());
}
...
As soon as I try to use the LIKE Operator like e.g.:
[FunctionName("GetToDoItem")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "gettodoitem")]
HttpRequest req,
[Sql("select [Id], [order], [title], [url], [completed] from dbo.ToDo where Id = #Id and title like '%Stackoverflow%'",
CommandType = System.Data.CommandType.Text,
Parameters = "#Id={Query.id}",
ConnectionStringSetting = "SqlConnectionString")]
IEnumerable<ToDoItem> toDoItem)
{
return new OkObjectResult(toDoItem.FirstOrDefault());
}
...
I'm getting an exception as follows:
Error indexing method 'GetToDoItem' '%Stackoverflow%' does not resolve to a value.
I understand, that this is due to the app setting lookup of the binding expressions, but I can't figure out a way to kind of "escape" these percentage signs. Currently, my only workaround is to execute the query manually.
Is there any other option to use the percentage sign for SQL like comparisons?
I've tried a double %% sign as well as escaping the % with a backslash.
This is a workaround solution.
If it turns out that there is a syntax to escape percent characters then this will be rendered immediately obsolete.
But one way of avoiding the issue will be to change the query as below
SELECT [Id],
[order],
[title],
[url],
[completed]
FROM dbo.ToDo
WHERE Id = #Id
AND title LIKE Concat(Char(37), 'Stackoverflow', Char(37))
This should get constant folded (in the SQL Server execution plan) to
title like '%Stackoverflow%'
without including any literal % in the actual query string.

Unable to select just certain columns from table with Entity Framework - get anonymous type error

I am trying to select only certain columns from a table using EF 6.1. However, it won't let me pull back just the columns I want. I have to pull back every column from the table which has 14,000 rows so the query takes ~30 seconds. The column that kills the query is a NVARCHAR in the table. But with EF it's all or nothing. I am using IEnumerable also. Perhaps I should be using IQueryable?>
Using this query I get an anonymous type error:
Using db As Ctx = New Ctx
Dim postcount = db.be_Posts.Count
posts = db.be_Posts.Select(Function(S) New With {S.DateCreated, S.Description, S.PostRowID, S.Title}).OrderByDescending(Function(x) x.DateCreated)
Return posts.ToList
End Using
Error:
Unable to cast object of type 'System.Data.Entity.Infrastructure.DbQuery`1[VB$AnonymousType_0`4[System.DateTime,System.String,System.Int32,System.String]]' to type 'System.Collections.Generic.IEnumerable`1
This works but is getting all the records and the columns I don't need:
Using db As Ctx = New Ctx
Dim postcount = db.be_Posts.Count
posts = db.be_Posts.OrderByDescending(Function(x) x.DateCreated).ToList
Return posts
End Using
What I would do is:
Create PostSummaryDto class:
public class PostSummaryDto
{
public DateTime DateCreated { get; set; }
...rest of fields...
}
Use PostSummaryDto class in query:
New PostSummaryDto { DateCreated = S.DateCreated, ...}
Define return type of function as IEnumerable<PostSummaryDto>.
I am not a fan of Visual Basic, so I am not sure if returning anonymous types is allowed, but I believe it is good custom to define return types clearly.

What if you don't need a parameter when querying with Dapper?

I have one query that does a count/group by where I don't need a parameter (there is no where clause).
What is the syntax to run a parameterless query with dapper?
var _results = _conn.Query<strongType>("Select Count(columnA) as aCount, ColumnB, ColumnC from mytable group by ColumnB, ColumnC");
does not work.
I've tried it a few different ways but I still keep getting "ArgumentNullException was unhandled by user code".
Tried to figure it out myself, searched all over and I'm giving up. Thanks in advance.
Edit: Below is the line of code from SqlMapper.cs that throws the error. It's line 1334
il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
The error details: Value cannot be null. Parameter name: con
Mapping a single result back works just fine:
var a = cnn.Query<int>("select 1").Single()
// a is 1
You may face trouble if somehow your query returns no results, for example:
select count(Id) from
(
select top 0 1 as Id, 2 as Title
) as X
group by Title
return 0 results, so doing a Single on an empty result set is not going to work.
try
var _results = _conn.Query("Select columnB, Count(columnA) C from mytable group by columnB");
int ColumnB = ((int)_results[0].ColumnB);
int C = ((int)_results[0].C);
Value cannot be null. Parameter name: con
This is error is thrown by several dynamic ORMs including Dappper, PetaPoco and Massive but it's usually the same problem: Make sure you're using the [Ignore] attribute on the properties you don't want to include. This includes properties inherited from base classes. The error is useless but that's what it means.
This error can occur because a property you're trying to set in your return object is get-only. Dapper, of course, requires being able to set all properties. You might consider having a separate database DTO object that then gets converted to your properly immutable domain object after reading from the database.
Change this:
public string MyProperty { get; }
to this:
public string MyProperty { get; set; }

Hierarchical Hibernate, how many queries are executed?

So I've been dealing with a home brew DB framework that has some seriously flaws, the justification for use being that not using an ORM will save on the number of queries executed.
If I'm selecting all possibile records from the top level of a joinable object hierarchy, how many separate calls to the DB will be made when using an ORM (such as Hibernate)?
I feel like calling bullshit on this, as joinable entities should be brought down in one query , right? Am I missing something here?
note: lazy initialization doesn't matter in this scenario as all records will be used.
Hibernate will almost always retrieve object hierarchies using a single query; I don't recall seeing it do otherwise. It's easy to test, anyway. With this very simple mapping:
#Entity
public static class Person {
#Id
public String name;
}
#Entity
public static class Student extends Person {
public float averageGrade;
}
#Entity
public static class Teacher extends Person {
public float salary;
}
Then Hibernate gives me the following results for a very simple browse query (sessionFactory.openSession().createCriteria(Person.class).list();).
With #Inheritance(strategy = InheritanceType.SINGLE_TABLE) on the parent:
select this_.name as name0_0_, this_.averageGrade as averageG3_0_0_,
this_.salary as salary0_0_, this_.DTYPE as DTYPE0_0_ from HibernateTest$Person this_
With #Inheritance(strategy = InheritanceType.JOINED) on the parent:
select this_.name as name0_0_, this_1_.averageGrade as averageG1_1_0_,
this_2_.salary as salary2_0_, case when this_1_.name is not null then 1
when this_2_.name is not null then 2 when this_.name is not null then 0
end as clazz_0_ from HibernateTest$Person this_ left outer
join HibernateTest$Student this_1_ on this_.name=this_1_.name left outer join
HibernateTest$Teacher this_2_ on this_.name=this_2_.name
With #Inheritance(strategy = InheritanceType.JOINED) on the parent:
select this_.name as name0_0_, this_.averageGrade as averageG1_1_0_,
this_.salary as salary2_0_, this_.clazz_ as clazz_0_ from
( select null as averageGrade, name, null as salary, 0 as clazz_
from HibernateTest$Person union select averageGrade, name, null as salary,
1 as clazz_ from HibernateTest$Student union select null as averageGrade,
name, salary, 2 as clazz_ from HibernateTest$Teacher ) this_
As you can see, each is one query, with JOINs or UNIONs as appropriate depending on the mapping type.
Bobah is right,
You should give hibernate a try in order to see how many request will be sent to the database, however, in hibernate you can also specify and tune specific request by using HQL.
In addition with hibernate tools, you could also use P6spy driver, so you'll be able to see all the request that hibernate send to your database, with the value for each filter of the request.

Random Row from SQL Server DB using DLINQ

I need to retrieve random rows from SQL Server database. I am looking for a way to achieve this using LINQ query. Is it possible?
SQL Query: SELECT [Id] FROM [MyTable] ORDER BY NEWID()
What is the equivalent LINQ query for the above SQL?
Thanks in advance.
Make a partial for your data context class and put in the following method:
partial class MyDataContext {
[Function(Name = "NEWID", IsComposable = true)]
public Guid Random()
{
return Guid.NewGuid();
}
}
Now you can compose this into your query and it'll get translated into calls to the sql newid() function like so:
from x in dc.MyEntities orderby dc.Random() select x.Id

Resources