row_number() over partition in linq - c#

My sql code is below, I'm trying to Convert it to linq. I'm getting stuck on how to do row_number() over (partition part. If i can get some guidance or assistance please and thank you.
with summary AS
(select * from
(select p.loan_guid,
p.TransactionDate,
p.balanceoutstanding,
row_number() over (partition by p.loan_guid
order By linenumber desc) as rk
from (select * from transactions1
where transactiondate <= #EndDate )as p )
as S where S.rk = 1)

I am having trouble finding a definitive answer, but my guess would be that Linq does not support analytic/window functions. If you are using Entity Framework, then you can always designate a type, execute the raw query and EF will map and track the results for you. Here is an example:
using(var ctx = new MyContext){
var myObjects = ctx.Products.SqlQuery("<Your Query>").ToList();
}
the result will be a list of objects of type Product.
This creates a dependency in your application on a SQL database, but I would prefer to have a clean SQL query that I can refactor later if necessary, Then an enormous Linq query in your code.

Related

How can I convert this sql query that reorders items in a database to linq?

I currently have a table where an item has a new order based on a column it's being sorted by. The goal of the sql statement is to reorder the table based on that sort column. The SQL Command currently works, but I have a lot of hard coded strings and I'm hoping to convert it to linq so it will be easier to test. The sql I have is below:
sql = string.Format(CultureInfo.InvariantCulture, "UPDATE x SET
x.[{1}] = x.[RowNum] FROM (SELECT [{1}], ROW_NUMBER() OVER (ORDER BY
t.[{1}] ASC, t.[Modified] DESC) AS RowNum FROM {0} t INNER JOIN
tableTwo i ON t.TableTwoId = i.Id INNER JOIN {4} p ON t.{4}Id
= p.Id WHERE i.{2} = {3} and {3} <> '' ", tableName, sortColumn, tableTwoColumn, "{0}", tableThreeName);
I'm familiar with basic Linq, but I'm not sure how to convert things like ROW_NUMBER() and OVER to linq. I changed the table names for sample names, in case it's not perfect. Any help would be appreciated!
Linq is for querying, not updating. You could possibly use EF or some other framework to update data but, honestly, raw SQL is best for bulk updating.
I would say that having a "sort" column that's based on existing data (and thus needs to be updated periodically) seems superfluous. Why not just order the data by that column in your select queries?

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

sp_executesql runs in milliseconds in SSMS but takes 3 seconds from ado.net [duplicate]

This question already has an answer here:
Stored Proc slower from application than Management Studio
(1 answer)
Closed 9 years ago.
This is my dynamic query used on search form which runs in milliseconds in SSMS roughly between 300 to 400 ms:
exec sp_executesql N'set arithabort off;
set transaction isolation level read uncommitted;
With cte as
(Select ROW_NUMBER() OVER
(Order By Case When d.OldInstrumentID IS NULL
THEN d.LastStatusChangedDateTime Else d.RecordingDateTime End
desc) peta_rn,
d.DocumentID
From Documents d
Inner Join Users u on d.UserID = u.UserID
Inner Join IGroupes ig on ig.IGroupID = d.IGroupID
Inner Join ITypes it on it.ITypeID = d.ITypeID
Where 1=1
And (CreatedByAccountID = #0 Or DocumentStatusID = #1 Or DocumentStatusID = #2 )
And (d.JurisdictionID = #3 Or DocumentStatusID = #4 Or DocumentStatusID = #5)
AND ( d.DocumentStatusID = 9 )
)
Select d.DocumentID, d.IsReEfiled, d.IGroupID, d.ITypeID, d.RecordingDateTime,
d.CreatedByAccountID, d.JurisdictionID,
Case When d.OldInstrumentID IS NULL THEN d.LastStatusChangedDateTime
Else d.RecordingDateTime End as LastStatusChangedDateTime,
dbo.FnCanChangeDocumentStatus(d.DocumentStatusID,d.DocumentID) as CanChangeStatus,
d.IDate, d.InstrumentID, d.DocumentStatusID,ig.Abbreviation as IGroupAbbreviation,
u.Username, j.JDAbbreviation, inf.DocumentName,
it.Abbreviation as ITypeAbbreviation, d.DocumentDate,
ds.Abbreviation as DocumentStatusAbbreviation,
Upper(dbo.GetFlatDocumentName(d.DocumentID)) as FlatDocumentName
From Documents d
Left Join IGroupes ig On d.IGroupID = ig.IGroupID
Left Join ITypes it On d.ITypeID = it.ITypeID
Left Join Users u On u.UserID = d.UserID
Left Join DocumentStatuses ds On d.DocumentStatusID = ds.DocumentStatusID
Left Join InstrumentFiles inf On d.DocumentID = inf.DocumentID
Left Join Jurisdictions j on j.JurisdictionID = d.JurisdictionID
Inner Join cte on cte.DocumentID = d.DocumentID
Where 1=1
And peta_rn>=#6 AND peta_rn<=#7
Order by peta_rn',
N'#0 int,#1 int,#2 int,#3 int,#4 int,#5 int,#6 bigint,#7 bigint',
#0=44,#1=5,#2=9,#3=1,#4=5,#5=9,#6=94200,#7=94250
This sql is formed in C# code and the where clauses are added dynamically based on the value the user has searched in search form. It takes roughly 3 seconds to move from one page to 2nd. I already have necessary indexes on most of the columns where I search.
Any idea why would my Ado.Net code be slow?
Update: Not sure if execution plans would help but here they are:
It is possible that SQL server has created inappropriate query plan for ADO.NET connections. We have seen similar issues with ADO, usual solution is to clear any query plans and run slow query again - this may create better plan.
To clear query plans most general solution is to update statistics for involved tables. Like next for you:
update statistics documents with fullscan
Do same for other tables involved and then run your slow query from ADO.NET (do not run SSMS before).
Note that such timing inconsistencies may hint of bad query or database design - at least for us that is usually so :)
If you run a query repeatedly in SSMS, the database may re-use a previously created execution plan, and the required data may already be cached in memory.
There are a couple of things I notice in your query:
the CTE joins Users, IGroupes and ITypes, but the joined records are not used in the SELECT
the CTE performs an ORDER BY on a calculated expression (notice the 85% cost in (unindexed) Sort)
probably replacing the CASE expression with a computed persisted column which can be indexed speeds up execution.
note that the ORDER BY is executed on data resulting from joining 4 tables
the WHERE condition of the CTE states AND d.DocumentStatusID = 9, but AND's other DocumentStatusIDs
paging is performed on the result of 8 JOINed tables.
most likely creating an intermediate CTE which filters the first CTE based on peta_rn improves performance
.net by default uses UTF strings, which equates to NVARCHAR as opposed to VARCHAR.
When you are doing a WHERE ID = #foo in dot net, you are likely to be implicitly doing
WHERE CONVERT(ID, NVARCHAR) = #foo
The result is that this where clause can't be indexed, and must be table scanned. The solution is to actually pass each parameter into the SqlCommand as a DbParameter with the DbType set to VARCHAR (in the case of string).
A similar situation could of course occur with Int types if the .net parameter is "wider" than the SQL column equivalent.
PS The easiest way to "prove" this issue is to run your query in SSMS with the following above
DECLARE #p0 INT = 123
DECLARE #p1 NVARCHAR = "foobar" //etc etc
and compare with
DECLARE #p0 INT = 123
DECLARE #p1 VARCHAR = "foobar" //etc etc

Improve query generated from entity framework

I have a query linq like this:
var query = from c in Context.Customers select c;
var result = query.ToList();
Linq query generate this tsql code:
exec sp_executesql N'SELECT
[Project1].[Id] AS [Id],
[Project1].[Name] AS [Name],
[Project1].[Email] AS [Email]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Email] AS [Email]
FROM [dbo].[Customers] AS [Extent1] ) AS [Project1]
Is there a way for not generate subquery?
Do you have any evidence that that query is causing performance problems? I imagine the query-optimizer would easily recognize that.
If you're certain after profiling that the query is a performance problem (doubtful) - and only then - you could simply turn the query into a stored procedure, and call that instead.
You use a tool like Linq because you don't want to write SQL, before abandoning that you should at least compare the query plan of your proposed SQL vs that generated by the tool. I don't have access to SQL Studio at the moment, but I would be a bit surprised if the query plans aren't identical...
EDIT: having had a chance to check out the query plans, they are in fact identical.
Short answer: No you cannot modify that query.
Long answer: If you want to reimplement Linq provider and query generator then perhaps there is a way but I doubt you want to do that. You can also implement custom EF provider wrapper which will take query passed from EF and reformat it but that will be hard as well - and slow. Are you going to write custom interpreter for SQL queries?

How do i modify Linq generated sql statement?

I have summarized my problem in following code.
NorthwindDataContext dc = new NorthwindDataContext();
var query = from c in dc.Customers
select c;
Above code is generating following sql statement
SELECT [t0].[ID], [t0].[FirstName], [t0].[LastName]
FROM [dbo].[Customer] AS [t0]
Now i want to modify the above generated query something like this
SELECT [t0].[ID], [t0].[FirstName], [t0].[LastName] FROM [dbo].[Customer]
AS [t0] WITH (nolock)
Is it possible in linq to modify the generated query?If yes then how?
You will not be able to modify the generated L2S T-SQL code directly, the way you want (unless you modify the transaction isolation level). However, we've dealt with situations like this, fairly simply, by creating a view with lock hints we want in place and querying the view, instead of the table directly.
I have found a very handy tips for modifying the linq generated sql statement.
NorthwindDataContext db = new NorthwindDataContext();
if (db.Connection.State == System.Data.ConnectionState.Closed)
db.Connection.Open();
var cmd = db.GetCommand(db.Customers.Where(p => p.ID == 1));
cmd.CommandText = cmd.CommandText.Replace("[Customers] AS [t0]", "[Customers] AS [t0] WITH (NOLOCK)");
var results = db.Translate(cmd.ExecuteReader());
Maybe these pages will help you..
http://www.infoq.com/news/2008/03/linq-nolock
http://coolthingoftheday.blogspot.com/2008/03/linq-to-sql-nolock.html
which refers hanselmans blog entry
http://www.hanselman.com/blog/GettingLINQToSQLAndLINQToEntitiesToUseNOLOCK.aspx
or check out this question
NOLOCK with Linq to SQL

Categories