Entity Framework v4.1 LIKE - c#

How do I have to build my query to result in an output SQL query like:
SELECT
[viewRegisters].[Id] AS [IdRegister]
WHERE Name LIKE '%a%bc'
OR
SELECT
[viewRegisters].[Id] AS [IdRegister]
WHERE Name LIKE 'a%b%c'
OR
SELECT
[viewRegisters].[Id] AS [IdRegister]
WHERE Name LIKE 'a%b%c%'
I'm using .Net Framework 4.0, Entity Framework v4.1 and C#.
EF v4.1 converts this type of linq queries from:
((IQueryable<T>)Data).Where(z => z.Field.Contains("a%b%c%"));
Into:
SELECT
[viewRegisters].[Id] AS [Id]
WHERE Name LIKE N'a~%b~%c~%' ESCAPE N'~'
That's not what I want. I want to be able to use the 'percent' symbol as I do directly in DB.

You must use ESQL if you want full wildcard support. Linq-to-entities is not able to do that and EFv4.1 code first (without EDMX) doesn't have support for model defined functions so the solution provided by #Johann Blais cannot be used.
I guess the code to run ESQL query can look like:
string command = "SELECT VALUE e FROM ContextName.DbSetName AS e WHERE e.Field LIKE 'a%b%c%'"
ObjectContext ctx = ((IObjectContextAdapter)dbContext).ObjectContext;
ObjectQuery<EntityType> query = new ObjectQuery<EntityType>(command, ctx);
ObjectResult<EtntiyType> result = query.Execute(MergeOption.AppendOnly);

If you are using SQL Server, use the PATINDEX function to do a pattern search. You can access this function through EF using the SqlFunctions class.
For example, the following EF query
context.ViewRegisters.Where(z => SqlFunctions.PatIndex("a%b%c%", z.Name) > 0);
will translate into
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name]
FROM [dbo].[ViewRegisters] AS [Extent1]
WHERE (CAST(PATINDEX(N'a%b%c%', [Extent1].[Name]) AS int)) > 0

var query = from viewRegister in context.ViewRegisters
where viewRegister.Name.Contains("yourname")
select viewRegister;

Related

Disable CAST AS to optimize query in Entity Framework

I'm using Entity Framework 5 and I want to select data from Oracle 10g database.
Problem is that the database table is huge and the query generated by Entity Framework is ineffective. I want to get rid of those CAST( [column] AS [type] ). Is there any setting to turn them off?
C# code:
var context = new APPDB();
var q = context.APP_TABLE.Where(i => i.ID == 123);
// This is how I did get the generated SQL query
var str = ((System.Data.Objects.ObjectQuery) q ).ToTraceString();
The generated query:
SELECT
CAST( "Extent1"."ID" AS number(10,0)) AS "C1",
"Extent1"."DESCRIPTION" AS "DESCRIPTION"
FROM "APP"."APP_TABLE" "Extent1"
WHERE (123 = ( CAST( "Extent1"."ID" AS number(10,0))))
What I want is the code to generate better performing query:
SELECT
"Extent1"."ID" AS "C1",
"Extent1"."DESCRIPTION" AS "DESCRIPTION"
FROM "APP"."APP_TABLE" "Extent1"
WHERE
"Extent1"."ID" = 123
Better later than never )
If you are using code first and manual mapping classes, use HasColumnType("INT") configuration for int properties.
For example:
var entity = builder.Entity<APP_TABLE>();
entity
.HasKey(x => x.ID)
.ToTable("APP_TABLE", "SCHEMA");
entity
.Property(x => x.ID)
.HasColumnType("INT");
I had a similar problem when using (short?) on the database and in an object property to perform the IQyueryable.
When using Equal() it usually do some bugs in code. When using the simple comparision, the T-SQL send an CAST() in two sides of the query. The bad thing: when using CAST in Transact SQL, Oracle does not use the INDEXES, making a simple select that runs in miliseconds direct in the database taking an eternity when running this way
Using this approach, the TSQL is transformed without the cast as an OR, that is less painfull than using the CAST. In case of using non nullable fields, the or does not appear, making the performance very high
In some cases, using Equal() gets rid of the cast conversion, but it not seems to work with short?
Lambda:
if (filter.Property.HasValue)
query = query.Where(w => new short?[] {
filter.Property}.Contains(w.Property));
SQL sent to Oracle:
WHERE (("Extent1"."Property" = :p__linq__0) OR (("Extent1"."Property" IS NULL) AND (:p__linq__0 IS NULL)))

How to convert this simple Entity Framework query into a standard SQL query?

I have no experience with the .NET Entity Framework and I have some doubts about what exactly do this query:
using (MyCorpo.EarlyWarnings.Model.EarlyWarningsEntities context = new Model.EarlyWarningsEntities())
{
DBContext.SetTimeout(context);
model.VulnerabilitySeverityAverage = (from x in context.VulnerabilityAlertDocuments select x.Severity).Average();
}
(Where the type of the model.VulnerabilitySeverityAverage is simply a string)
So I think that VulnerabilityAlertDocuments map the VulnerabilityAlertDocument database table because into the EarlyWarningsEntities I have something this line:
public DbSet<VulnerabilityAlertDocument> VulnerabilityAlertDocuments { get; set; }
So I am executing a query on the VulnerabilityAlertDocuments DbSet object that represent a query on my VulnerabilityAlertDocument table on my database. Is it correct?
So what exatly do the previous query?
I think that it select the Severity field value of all records in the VulnerabilityAlertDocument table and calculate the avarage value from all these value.
Is it my reasoning correct?
How can I convert this entity query in a classic SQL query? Someone can help me?
Tnx
How can I convert this entity query in a classic SQL query?
To see actual SQL you can just call .ToString() method on your query;
var sql = (from x in context.VulnerabilityAlertDocuments select x.Severity).Average().ToString();
So I am executing a query on the VulnerabilityAlertDocuments DbSet
object that represent a query on my VulnerabilityAlertDocument table
on my database. Is it correct?
Yes
So what exatly do the previous query?
Your query will average value in Severity column of ValnerabilityAlertDocuments table.
your translated query would've looked simular to this:
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
AVG([Extent1].[Severity]) AS [A1]
FROM [dbo].[ValnerabilityAlertDocuments] AS [Extent1]
) AS [GroupBy1]
Also you could try to use such tool as SQL Server Profiler
UPDATE:
Just adding LinqPad to list of tools (thanks to Dismissile)
Select Average(x.Severity)
From VulnerabilityAlertDocuments x
Thats assuming your table is called "VulnerabilityAlertDocuments"
try again

Rewrite SQL to FluentNHibernate

I'am using NHibernate 3.3.1.4000 and FluentNHibernate 1.3.0.733 with SQL Server 2012 and I need to rewrite query to IQueryOver to do this calculation on server side without stored procedure calling.
WITH CTE_Links AS
(
SELECT Article1, MIN(Article2) Article2
FROM dbo.LinkBetweenArticles
GROUP BY Article1
HAVING Article1 > MIN(Article2)
)
SELECT COUNT(*)
FROM dbo.ArticlePlacedBySeller a
LEFT JOIN CTE_Links l ON a.Id = l.Article1
WHERE l.Article2 IS NULL
AND ConfirmedPosition_Id = 1000
Script description can be read here if you need
as far as I know it is not possible to use natively IQueryOver API to achieve this. IMHO you could use this CTE query as a custom query. You can find the solution by following the link http://refactoringaspnet.blogspot.com/2011/04/using-common-table-expressions-to.html.

Retrieve LINQ to sql statement (IQueryable) WITH parameters

I'm trying to figure out if there's a way to retrieve the (full) sql statement that gets executed on the database server.
I found something already, but it does not exactly what I would like:
IQueryable<SomeType> someQuery = ...
string command = dataContext.GetCommand(query).CommandText;
In my case this gives me a command string something like:
SELECT TOP (50) [t0].[ID], ....
FROM [dbo].[someTable] AS [t0]
WHERE ([t0].[someColumn] IS NOT NULL) AND (([t0].[someColumn]) IN (#p0))
On database there's executed:
exec sp_executesql N'SELECT TOP (50) [t0].[ID], ...
FROM [dbo].[someTable] AS [t0]
WHERE ([t0].[someColumn] IS NOT NULL) AND (([t0].[someColumn]) IN (#p0, #p1))',N'#p0 int,#p1 int',#p0=401,#p1=201
Is there a way to retrieve this 'full' statement (so also the parameter values) from C# code?
You can also see the generated sql query if you have an instance of
IQueryable<T> and call the .ToString() method.
For Example:
var db = new DbContext();
IQueryable<Blog> query = db.Blog.Where(tt=> tt.Id > 100).OrderByDescending(tt=>tt.Id);
var sqlString = query.ToString();
Console.WriteLine(sqlString);
This will generate an output of:
SELECT [Extent1].[Id] AS [Id],
[Extent1].[Title] AS [Title],
[Extent1].[Author] AS [Author],
[Extent1].[Text] AS [Text],
[Extent1].[CreatedAt] AS [CreatedAt],
[Extent1].[UpdatedAt] AS [UpdatedAt]
FROM [dbo].[Blogs] AS [Extent1]
WHERE [Extent1].[Id] > 100
ORDER BY [Extent1].[Id] DESC
Once you get the Command you can print the CommandText and then loop through the Parameters collection and print all the individual parameters.
Also there is the linq-to-sql debug visualizer which does the same in debug mode.
A really nice tool to view the queries as they are happening is the Linq-to-sql profiler
In the latest version of EF Core 5 ToQueryString,
query.ToQueryString()
(SqlCommand)dataContext.GetCommand(query)
will give you access to Parameters collection.
I'm using Datacontext.Log property to get the generated SQL Statement (it includes the statement text, and parameters).
Just set YourDataContext.Log = SomeTextWriter.
It can be written to a file (Log = new StreamWriter(#"c:\temp\linq.log")) or to debug window, see this post
When viewing the IQueryable in the Locals pane, you can access DebugView > Query, which will contain the SQL statement.

Select N Random Rows with Fluent NHibernate

How do I retrieve N random entities using Fluent NHibernate?
Desired query:
SELECT TOP 5 * FROM MyTable ORDER BY newid()
I'd like to be able to use the Linq repo's for this, but I'm not sure if the result will be optimal. I am not familiar with HQL.
SQL Server-specific Solution
Where Word is the random entity:
IQuery q = _unitOfWork.CurrentSession
.CreateQuery("from Word order by newid()")
.SetMaxResults(5);
var randomWords = q.List<Word>();
Side note: FluentNHibernate is not for querying, it is for mapping and configuration only. Querying is part of "pure" NHibernate.
You can't do it using LINQ directly. The function newid() is SQL Server-specific, so there's no direct equivalent in NHibernate. What you can do here is to query using native SQL by using ISession's CreateSQLQuery method.
See also here for more "deep into NHibernate" method:
How do I select a Random Row using NHibernate's ICriteria API?
You can use Take/Skip linq extensions:
var resultSet = session.Query<TestTable>().Skip(5).Take(10);
With PostgreSql DB this expands to the following SQL statement:
select TestTable.Id, TestTable.Field from TestTable
LIMIT :p0 OFFSET :p1;

Categories