Linq query to SQL query - c#

I have a Linq Query that works well but I need to write the SQL Query
Can Anybody help me write it?
this query will search the database foreach a.h and a.HV in the view with the filters of time and model and in the end it checks the option Filter.M that if it is selected it will search for all the data selected in this DropDownCheckBoxes`
How can i write the this where and select part in SQL command?
ret1 = (from a in View
where
a.LastRefreshTime>=Filter.From && a.LastRefreshTime<=Filter.To && a.ModelCode == mdlCode &&
Filter.PN.Select(epn => epn.Substring(0, 11)).Contains(a.H) &&
Filter.PN.Select(epn => epn.Substring(14, 2)).Contains(a.HV)
select new RData
{
v = a.v,
Date = a.LastRefreshTime,
UserId = a.UserId,
M = a.Name,
}).Distinct().AsQueryable();
ret = ret1.Where(nr =>
Filter.M == null || !Filter.M.Any() || Filter.M.Contains(nr.M)
).ToList();

Here's a start for you
select a.v v,
a.LastRefreshTime "Date",
a.UserId,
a.Name
from a
where a.LastRefreshTime>= arg_filter_from
and a.LastRefreshTime<= arg_filter_to
and a.ModelCode = arg_mdlCode
.
.
.
In this query you'll need to replace 'arg_...' with the appropriate values or arguments you want.
Contains is roughly equivalent to "IN" in SQL. For example:
where a.Name in ('jim', 'bob', 'joe')
In can also be used with a subselect which is roughly what I think Filter.PN.Select is doing though I'm not a linq expert. Example:
where a.H in (Select foo from PN_Table)
Or simpler example continuing on the my previous name example:
where a.Name in (select first_name from table)

If we supposed that the Filter.PN list represent a table FilterPN in your sql database, that will be your converted code for the first linq query
select distinct a.v, a.LastRefreshTime, a.UserId, a.Name
from [view] a
where a.LastRefreshTime>= 'Filter.From' and
a.LastRefreshTime<='Filter.To' and a.ModelCode = 'mdlCode' and
exists(select top 1 * from FilterPN where Substring(epn, 1, 11) = a.H) and
exists(select top 1 * from FilterPN where Substring(eenter code herepn, 15, 2) = a.HV)
think to replace the enquoted variables with ur real values 'Filter.To'...

Related

Improving LINQ query for many-to-many relation

I have a database with the following schema:
Now, I'm trying to pull all landingpages for a domain and sort those by the first UrlFilter's FilterType that matches a certain group. This is the LINQ I've come up with so far:
var baseQuery = DbSet.AsNoTracking()
.Where(e => EF.Functions.Contains(EF.Property<string>(e, "Url"), $"\"{searchTerm}*\""))
.Where(e => e.DomainLandingPages.Select(lp => lp.DomainId).Contains(domainId));
var count = baseQuery.Count();
var page = baseQuery
.Select(e => new
{
LandingPage = e,
UrlFilter = e.LandingPageUrlFilters.FirstOrDefault(f => f.UrlFilter.GroupId == groupId)
})
.Select(e => new
{
e.LandingPage,
FilterType = e.UrlFilter == null ? UrlFilterType.NotCovered : e.UrlFilter.UrlFilter.UrlFilterType
})
.OrderBy(e => e.FilterType)
.Skip(10).Take(75).ToList();
Now, while this technically works, it's quite slow with execution times ranging from 10-30 seconds, which is not good enough for the use case. The LINQ is translated to the following SQL:
SELECT [l1].[Id], [l1].[LastUpdated], [l1].[Url], CASE
WHEN (
SELECT TOP(1) [l].[LandingPageId]
FROM [LandingPageUrlFilters] AS [l]
INNER JOIN [UrlFilters] AS [u] ON [l].[UrlFilterId] = [u].[Id]
WHERE ([l1].[Id] = [l].[LandingPageId]) AND ([u].[GroupId] = #__groupId_3)) IS NULL THEN 4
ELSE (
SELECT TOP(1) [u0].[UrlFilterType]
FROM [LandingPageUrlFilters] AS [l0]
INNER JOIN [UrlFilters] AS [u0] ON [l0].[UrlFilterId] = [u0].[Id]
WHERE ([l1].[Id] = [l0].[LandingPageId]) AND ([u0].[GroupId] = #__groupId_3))
END AS [FilterType]
FROM [LandingPages] AS [l1]
WHERE CONTAINS([l1].[Url], #__Format_1) AND #__domainId_2 IN (
SELECT [d].[DomainId]
FROM [DomainLandingPages] AS [d]
WHERE [l1].[Id] = [d].[LandingPageId]
)
ORDER BY CASE
WHEN (
SELECT TOP(1) [l2].[LandingPageId]
FROM [LandingPageUrlFilters] AS [l2]
INNER JOIN [UrlFilters] AS [u1] ON [l2].[UrlFilterId] = [u1].[Id]
WHERE ([l1].[Id] = [l2].[LandingPageId]) AND ([u1].[GroupId] = #__groupId_3)) IS NULL THEN 4
ELSE (
SELECT TOP(1) [u2].[UrlFilterType]
FROM [LandingPageUrlFilters] AS [l3]
INNER JOIN [UrlFilters] AS [u2] ON [l3].[UrlFilterId] = [u2].[Id]
WHERE ([l1].[Id] = [l3].[LandingPageId]) AND ([u2].[GroupId] = #__groupId_3))
END
OFFSET #__p_4 ROWS FETCH NEXT #__p_5 ROWS ONLY
Now my question is, how can I improve the execution time of this? Either by SQL or LINQ
EDIT: So I've been tinkering with some raw SQL and this is what I've come up with:
with matched_urls as (
select l.id, min(f.urlfiltertype) as Filter
from landingpages l
join landingpageurlfilters lpf on lpf.landingpageid = l.id
join urlfilters f on lpf.urlfilterid = f.id
where f.groupid = #groupId
and contains(Url, '"barz*"')
group by l.id
) select l.id, 5 as Filter
from landingpages l
where #domainId in (
select domainid
from domainlandingpages dlp
where l.id = dlp.landingpageid
) and l.id not in (select id from matched_urls ) and contains(Url, '"barz*"')
union select * from matched_urls
order by Filter
offset 10 rows fetch next 30 rows only
This performs somewhat okay, cutting the execution time down to ~5 seconds. As this is to be used for a table search I would however like to get it down even further. Is there any way to improve this SQL?
You're right to have a look at the generated SQL. In general, I would advise to learn SQL, write a performing SQL query and work your way back (either use a stored procedure or raw SQL, or design your LINQ query with that same philosophy.
I suspect this will be better (not tested):
var page = (
from e in baseQuery
let urlFilter = e.LandingPageUrlFilters.OrderBy(f => f.UrlFilterType).FirstOrDefault(f => f.UrlFilter.GroupId == groupId)
let filterType = urlFilter == null ? UrlFilterType.NotCovered : e.UrlFilter.UrlFilter.UrlFilterType
select new
{
LandingPage = e,
FilterType = filterType
}
).Skip(10).Take(75).ToList();
one of the way to improve the execution time is see execution plan in SSMS (SQL Server Management Studio).
After look on the execution plan you can design some indexes, or if you have no experiences with this, you can see if SSMS recommends some indexes.
Next try to create the indexes and execute the query again and see if execution time was improved.
Note: this is only one of many possible ways to improve execution time...

SQL inner select to LINQ

This thing is driving me crazy.
I think its not that complicated but I don't get it.
I have this working SQL statement and I need the Linq statement for it.
select
a.id, a.date,
(select top 1 b.price from b where a.id = b.id and a.date >= b.date) as price
from a;
For explanation:
I have a table a with articles and a table b with a price history.
Now I need a datagrid where I can enter new entries for table a (so a view is not working) and after saving its showing me associated price
I hope I could express myself understandably
For translating SQL to LINQ query comprehension:
Translate FROM subselects as separately declared variables.
Translate each clause in LINQ clause order, leaving monadic operators (DISTINCT, TOP, etc) as functions applied to the whole LINQ query.
Use table aliases as range variables. Use column aliases as anonymous type field names.
Use anonymous types (new { }) for multiple columns
Left Join is simulated by using a into join_variable and doing another from from the join variable followed by .DefaultIfEmpty().
Replace COALESCE with the conditional operator and a null test.
SELECT * must be replaced with select range_variable or for joins, an anonymous object containing all the range variables.
SELECT fields must be replaced with select new { ... } creating an anonymous object with all the desired fields or expressions.
Proper FULL OUTER JOIN must be handled with an extension method.
For your query:
var ans = from ra in a
select new {
ra.id,
ra.date,
price = (from rb in b
where ra.id == rb.id && ra.date >= rb.date
select rb.price).First()
};
I'm not sure which syntax you're aiming for, but one of these should do the trick. I haven't tested it though.
from xa in a
select new
{
id,
date,
price = (
from xb in b
where xa.id == xb.id && xa.date >= xb.date
select xb.price
).First() // or .FirstOrDefault() if you want to allow null prices
};
or
a.Select(xa => new
{
id,
date,
price = b.First(xb => xa.id == xb.id && xa.date >= xb.date) // or .FirstOrDefault() if you want to allow null prices
});

Convert SQL to EF Linq

I have the following query:
SELECT COUNT(1)
FROM Warehouse.WorkItems wi
WHERE wi.TaskId = (SELECT TaskId
FROM Warehouse.WorkItems
WHERE WorkItemId = #WorkItemId)
AND wi.IsComplete = 0;
And since we are using EF, I'd like to be able to use the Linq functionality to generate this query. (I know that I can give it a string query like this, but I would like to use EF+Linq to generate the query for me, for refactoring reasons.)
I really don't need to know the results of the query. I just need to know if there are any results. (The use of an Any() would be perfect, but I can't get the write code for it.)
So... Basically, how do I write that SQL query as a LINQ query?
Edit: Table Structure
WorkItemId - int - Primary Key
TaskId - int - Foreign Key on Warehouse.Tasks
IsComplete - bool
JobId - int
UserName - string
ReportName - string
ReportCriteria - string
ReportId - int - Foreign Key on Warehouse.Reports
CreatedTime - DateTime
The direct translation could be something like this
var result = db.WorkItems.Any(wi =>
!wi.IsComplete && wi.TaskId == db.WorkItems
.Where(x => x.WorkItemId == workItemId)
.Select(x => x.TaskId)
.FirstOrDefault()));
Taking into account the fact that SQL =(subquery), IN (subquery) and EXISTS(subquery) in nowadays modern databases are handled identically, you can try this instead
var result = db.WorkItems.Any(wi =>
!wi.IsComplete && db.WorkItems.Any(x => x.WorkItemId == workItemId
&& x.TaskId == wi.TaskId));
Turns out that I just needed to approach the problem from a different angle.
I came up with about three solutions with varying Linq syntaxes:
Full method chain:
var q1 = Warehouse.WorkItems
.Where(workItem => workItem.TaskId == (from wis in Warehouse.WorkItems
where wis.WorkItemId == workItemId
select wis.TaskId).First())
.Any(workItem => !workItem.IsComplete);
Mixed query + method chain:
var q2 = Warehouse.WorkItems
.Where(workItem => workItem.TaskId == Warehouse.WorkItems
.Where(wis => wis.WorkItemId == workItemId)
.Select(wis => wis.TaskId)
.First())
.Any(workItem => !workItem.IsComplete);
Full query:
var q3 = (from wi in Warehouse.WorkItems
where wi.TaskId == (from swi in Warehouse.WorkItems
where swi.WorkItemId == workItemId
select swi.TaskId).First()
where !wi.IsComplete
select 1).Any();
The only problems with this is that it comes up with some really jacked up SQL:
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [Warehouse].[WorkItems] AS [t0]
WHERE (NOT ([t0].[IsComplete] = 1)) AND ([t0].[TaskId] = ((
SELECT TOP (1) [t1].[TaskId]
FROM [Warehouse].[WorkItems] AS [t1]
WHERE [t1].[WorkItemId] = #p0
)))
) THEN 1
ELSE 0
END) AS [value]
You can use the Any() function like so:
var result = Warehouse.WorkItems.Any(x => x.WorkItemId != null);
In short, you pass in your condition, which in this case is checking whether or not any of the items in your collection have an ID
The variable result will tell you whether or not all items in your collection have ID's.
Here's a helpful webpage to help you get started with LINQ: http://www.dotnetperls.com/linq
Subquery in the original SQL was a useless one, thus not a good sample for Any() usage. It is simply:
SELECT COUNT(*)
FROM Warehouse.WorkItems wi
WHERE WorkItemId = #WorkItemId
AND wi.IsComplete = 0;
It looks like, since the result would be 0 or 1 only, guessing the purpose and based on seeking how to write Any(), it may be written as:
SELECT CASE WHEN EXISTS ( SELECT *
FROM Warehouse.WorkItems wi
WHERE WorkItemId = #WorkItemId AND
wi.IsComplete = 0 ) THEN 1
ELSE 0
END;
Then it makes sense to use Any():
bool exists = db.WorkItems.Any( wi => wi.WorkItemId == workItemId & !wi.IsComplete );
EDIT: I misread the original query in a hurry, sorry. Here is an update on the Linq usage:
bool exists = db.WorkItems.Any( wi =>
db.WorkItems
.SingleOrDefault(wi.WorkItemId == workItemId).TaskId == wi.TaskId
&& !wi.IsComplete );
If the count was needed as in the original SQL:
var count = db.WorkItems.Count( wi =>
db.WorkItems
.SingleOrDefault(wi.WorkItemId == workItemId).TaskId == wi.TaskId
&& !wi.IsComplete );
Sorry again for the confusion.

Linq-to-SQL: arithmetic operation on consecutive elements

For example, I have a table:
Date |Value
----------|-----
2015/10/01|5
2015/09/01|8
2015/08/01|10
Is there any way using Linq-to-SQL to get a new sequence which will be an arithmetic operation between consecutive elements in the previously ordered set (for example, i.Value - (i-1).Value)? It must be executed on SQL Server 2008 side, not application side.
For example dataContext.GetTable<X>().OrderByDescending(d => d.Date).Something(.......).ToArray(); should return 3, 2.
Is it possible?
You can try this:
var q = (
from i in Items
orderby i.ItemDate descending
let prev = Items.Where(x => x.ItemDate < i.ItemDate).FirstOrDefault()
select new { Value = i.ItemValue - (prev == null ? 0 : prev.ItemValue) }
).ToArray();
EDIT:
If you slightly modify the above linq query to:
var q = (from i in Items
orderby i.ItemDate descending
let prev = Items.Where(x => x.ItemDate < i.ItemDate).FirstOrDefault()
select new { Value = (int?)i.ItemValue - prev.ItemValue }
).ToArray();
then you get the following TSQL query sent to the database:
SELECT ([t0].[ItemValue]) - ((SELECT [t2].[ItemValue]
FROM (SELECT TOP (1) [t1].[ItemValue]
FROM [Items] AS [t1]
WHERE [t1].[ItemDate] < [t0].[ItemDate]) AS [t2]
)) AS [Value]
FROM [Items] AS [t0]
ORDER BY [t0].[ItemDate] DESC
My guess now is if you place an index on ItemDate field this shouldn't perform too bad.
I wouldn't let SQL do this, it would create an inefficient SQL query (I think).
I could create a stored procedure, but if the amount of data is not too big I can also use Linq to objects:
List<x> items=dataContext.GetTable<X>().OrderByDescending(d => d.Date).ToList();//Bring data to memory
var res = items.Skip(1).Zip(items, (cur, prev) => cur.Value - prev.Value);
At the end, I might use a foreach for readability

how to convert this T-SQL statment to linq

i'm starter in linq, i have write this T-SQL Query
select * from DOCUMENT_TYPES where document_id in(
select document_id from Clearance_Document where Clearance_id=(select clearance_id from clearance_id from request where request_id=3))
i want convert this T-SQL Query to linq, please help me, thanks
Well, I would start first by refactoring your SQL into something other than a chain of nested sub-queries. I think this ought to do the same thing, and it's much more readable:
SELECT
*
FROM
DOCUMENT_TYPES dt
JOIN
Clearance_Document cd
ON
dt.document_id = cd.document_id
JOIN
Request r
ON
cd.clearance_id = r.clearance_id
WHERE
r.request_id = 3
(I'm assuming that from clearance_id from request was a typo.)
Then you can easily refactor into a LINQ statement:
var result = from dt in DOCUMENT_TYPES
join cd in Clearance_Document on dt.document_id equals cd.document_id
join r in Request on cd.clearance_id equals r.clearance_id
where r.request_id = 3
select new {
property1 = dt.something,
property2 = cd.somethingElse,
...
};
var result =
from a in DOCUMENT_TYPES
let list =
(
from b in Clearance_Document
where b.Clearance_id == (from c in clearance_id where request_id == 3).First<string>())
select b
).ToList()
where list.Contains(a.document_id)
select a;
Something like that should do (i guessed you're using EF, but you can easyly adapt to other LinQ-Types):
context.Document_Types.Where(doc =>
conext.Clearance_Document.Where(cd =>
cd.Clearance_Id == context.Request.Single(r => r.Request_Id == 3)
).Contains(doc.Document_Id)
).ToList();
How about
var result = c.Id context.Request.Single(r => r.Id == 3)
.Clearances.SelectMany(c => x.DocumentTypes);
In effect, get the one and only Request with an Id equal to 3, then get all the DocumentTypes of all its Clearances.
If your database is set up with the appropriate foreign keys these relationships will be automatically generated as part of your model.

Categories