How to replicate in LINQ a SQL query that uses Coalesce to pivot rows into a single column - linq

How can I achieve this functionality from SQL in LINQ?
Here I am getting 3 SP Number to one Contract ID:
DECLARE #Names VARCHAR(8000)
SELECT #Names = COALESCE( #Names + ', ', '') + us.SP_NBR
FROM CAATS_ADMIN.CONTRACT_SP us
WHERE US.CNTRCT_ID='1000038'

You can use the LINQ aggregate function. You will need to retrieve the data in a SELECT to a list of strings through whatever data access mechanism you are using then you use the Aggregate like this:
List<string> source = GetMyData();
var b = source.Aggregate ("",
(current, s)=> string.Concat(current, string.Format("{0},", s)) );
This applies the string concatenation to every item in the sequence to build a single string.

Related

List of multiple column condition in query (kind of batch)

when trying to search with single record then this query works
#Query(value = "select * from table t where t.column1 = :column1 and t.column2 = :column2 and t.column3 = :column3")
Flux<Invoice> findByMultipleColumn(#Param("column1”) String column1, #Param("column2”) String column2, #Param("column3”) String column3);
But when I have list of criterias instead of a single row condition then I have to loop over the list of criterias & call the above query multiple times which is not feasible solution.
Sudo code
for (Criteria criteria : criteriaList) {
repository.findByMultipleColumn(criteria.getColumn1(), criteria.getColumn2(), criteria.getColumn3());
}
What I am trying to find a way to solve the above query for multiple LIST of all the 3 column criteria pair, something like below (this is not working solution)
#Query(value = "select * from table t where t.column1 = :column1 and t.column2 = :column2 and t.column3 = :column3")
Flux<Invoice> findByMultipleColumn(#Param List<Table> table);
Is there any way somehow we can try to achieve the above case?
Would be doable if column1, 2 and 3 were Embedded, then you could do
#Query(select * from Entity where embeddedProperty in (:values))
Flux<Entity> findByEmbeddedPropertyIn(Collection<EmbeddedClas> values);
Which would generate the following native SQL clause
Where (column1, column2, column3) in ((x, y, z), ...)
If you don't want to pack these fields i to an embeddable class, you can also try to do a workaround
#Query(select * from Entity where Concat(column1, ';', column2, ';', column3) in (:parametersConcatrenatedInJava)
Flux<Entity> findBy3Columns(Collection<String> parametersConcatrenatedInJava);
It's ofcourse not bulletproof, all three columns could have ";" as their values, this might be problematic if their type is not string, etc.
Edit.:
Third option is to use specification api. Using the criteria builder you can concatenate multiple and / or queries. And pass that specification as an argument to the repository that extends JpaSpecificationExecutor (if you're fetching whole entities) or an entity manager if you're using projections. Read more about specifications

ASP.net LINQ on DataView to use Like query

I want to filter a DataView but DV.Rowfilter is taking too much time .
dv.RowFilter = "ProductName like '%" + searchtxt + "%'";
So I decided to use the LINQ but how to implement above like query in LINQ ?
LINQ is not more efficient in general, but it can increase readability and maintainability.
So you can try Linq-To-DataSet:
var query = from row in dv.Table.AsEnumerable()
let productName = row.Field<string>("ProductName")
where productName.Contains(searchtxt)
select row;
DataTable tbl = query.CopyToDataTable(); // use this as DataSource or use tbl.DefaultView
Here the same with method syntax:
var query = dv.Table.AsEnumerable()
.Where(row => row.Field<string>("ProductName").Contains(searchtxt));
MSDN: Creating a DataView Object with LINQ to DataSet
i have tried your second solution, but now its throwing the exception
"The source contains no DataRows." and actually the DataTable which i
make as DataTable.AsEnumerable() , it has the rows in it
The table contains rows but the filter skips all of them.
You could use if(query.Any()){...} to check if there are rows:
DataTable tbl = dv.Table.Clone(); // creates an empty table with the same columns
if(query.Any())
tbl = query.CopyToDataTable();

How this linq execute?

Data = _db.ALLOCATION_D.OrderBy(a => a.ALLO_ID)
.Skip(10)
.Take(10)
.ToList();
Let say I have 100000 rows in ALLOCATION_D table. I want to select first 10 row. Now I want to know how the above statement executes. I don't know but I think it executes in the following way...
first it select the 100000 rows
then ordered by ALLO_ID
then Skip 10
finally select the 10 rows.
Is it right? I want to know more details.
This Linq produce a SQL query via Entity Framework. Then it depends on your DBMS, but for SQL Server 2008, here is the query produces:
SELECT TOP (10) [Extent1].[ALLO_ID] AS [ALLO_ID],
FROM (
SELECT [Extent1].[ALLO_ID] AS [ALLO_ID]
, row_number() OVER (ORDER BY [Extent1].[ALLO_ID] ASC) AS [row_number]
FROM [dbo].[ALLOCATION_D] AS [Extent1]
) AS [Extent1]
WHERE [Extent1].[row_number] > 10
ORDER BY [Extent1].[ALLO_ID] ASC
You can run this in your C# for retrieve the query:
var linqQuery = _db.ALLOCATION_D
.OrderBy(a => a.ALLO_ID)
.Skip(10)
.Take(10);
var sqlQuery = ((System.Data.Objects.ObjectQuery)linqQuery).ToTraceString();
Data = linqQuery.ToList();
Second option with Linq To SQL
var linqQuery = _db.ALLOCATION_D
.OrderBy(a => a.ALLO_ID)
.Skip(10)
.Take(10);
var sqlQuery = _db.GetCommand(linqQuery).CommandText;
Data = linqQuery.ToList();
References:
How do I view the SQL generated by the entity framework?
How to: Display Generated SQL
How to view LINQ Generated SQL statements?
Your statement reads as follows:
Select all rows (overwritten by skip/take)
Order by Allo_ID
Order by Allo_ID again
Skip first 10 rows
Take next 10 rows
If you want it to select the first ten rows, you simply do this:
Data = _db.ALLOCATION_D // You don't need to order twice
.OrderBy(a => a.ALLO_ID)
.Take(10)
.ToList()
Up to the ToList call, the calls only generates expressions. That means that the OrderBy, Skip and Take calls are bundled up as an expression that is then sent to the entity framework to be executed in the database.
Entity framework will make an SQL query from that expression, which returns the ten rows from the table, which the ToList methods reads and places in a List<T> where T is the type of the items in the ALLOCATION_D collection.

LINQ query (or lambda expression) to return records that match a list

I have a list of strings (converted from Guid) that contains the ID's of items I want to pull from my table.
Then, in my LINQ query, I am trying to figure out how to do an in clause to pull records that are in that list.
Here is the LINQ
var RegionRequests = (from r in db.course_requests
where PendingIdList.Contains(r.request_state.ToString())
select r).ToList();
It builds, but I get a run error: "System.NotSupportedException: LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression".
I would prefer to compare guid to guid, but that gets me nowhere.
Can this be converted to a lambda expression? If that is best, how?
LINQ to Entites tries to convert your expression to an SQL Statement. Your server didn't know the stored procedure ToString().
Fix:
var regionRequests =
from r in db.course_requests.ToList()
where PendingIdList.Contains(r.request_state.ToString())
select r;
With db.course_requests.ToList() you force LINQ to materialize your database data (if big table, you gonna have a bad time) and the ToString() is executed in the object context.
You stated: I have a list of strings (converted from Guid) ...
Can you NOT convert them into strings and keep it as a List< System.Guid>?? Then you can do this (assuming PendingIdGuidList is List< System.Guid>:
var regionRequets = (from r in db.course_requests
join p in PendingIdGuidList on u.request_state equals p
select r).ToList();
Edited to add:
I ran a test on this using the following code:
var db = new EntityModels.MapleCreekEntities();
List<System.Guid> PendingIdGuidList =
new List<System.Guid>() {
System.Guid.Parse("77dfd79e-2d61-40b9-ac23-36eb53dc55bc"),
System.Guid.Parse("cd409b96-de92-4fd7-8870-aa42eb5b8751")
};
var regionRequets = (from r in db.Users
join p in PendingIdGuidList on r.Test equals p
select r).ToList();
Users is a table in my database. I added a column called Test as a Uniqueidentifier data type, then modified 2 records with the following Guids.
I know it's not exactly a 1:1 of what the OP is doing, but pretty close. Here is the profiled SQL statement:
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[UserLogin] AS [UserLogin],
[Extent1].[Password] AS [Password],
[Extent1].[Test] AS [Test]
FROM [dbo].[Users] AS [Extent1]
INNER JOIN (SELECT
cast('77dfd79e-2d61-40b9-ac23-36eb53dc55bc' as uniqueidentifier) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
cast('cd409b96-de92-4fd7-8870-aa42eb5b8751' as uniqueidentifier) AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1] ON [Extent1].[Test] = [UnionAll1].[C1]

Adding a random Guid column to a Linq to Entities query to grab random records

I've found some articles about using the RandomView view and the GetNewID function to pull back randomized records, but they are using this method with Linq to SQL which allows Functions and Stored Procs to be used with no return value or a scalar return value. From what I understand, a Stored Proc has to been returned as one of the Entity Framework objects from my generated model. I have been able to get that to work as an object, but not returning a scalar or no return set.
What I want to do is to simply add a column to my Linq query that contains a newly generated Guid so that I can order by the new Guids and take a specific number of records randomly. Can anyone help with some sort of lambda expression or join that would enable me to do this? It seems like it should be something built into EF, but I understand that we are on EF v1.
(Please provide code in VB.net)
In the Select clause of your Linq query, you should be able to insert a GUID like this:
var result = from myRecord in myTable
select new {
field1 = myRecord.field1,
field2 = myRecord.field2,
guidField = Guid.NewGuid()
};
Well, my VB is a little rusty, but I think this will work...
Dim result =
From myRecord in myTable _
Select field1, _
field2, _
guidField = System.Guid.NewGuid()

Resources