Get SQL statement from a predicate? - c#

Is it possible to build the 'WHERE' clause of a SQL statement based on a predicate?
For example:
public override IQueryable<Customer>
SearchFor(Expression<Func<Customer, bool>> predicate)
{ }
The base method just uses EF and all it does is:
return dbSet.Where(predicate);
However, in this particular scenario I need to override the method and, based on the predicate parameter, build a sql statement and execute that statement against the database directly (skipping EF).
So my new method would be:
public override IQueryable<Customer> SearchFor(Expression<Func<Customer, bool>> predicate)
{
var where = predicate.ToString(); //Not actual code!!
var sql = "SELECT id, name FROM customers WHERE " + where;
//Execute sql statement
}
And the caller would do:
var customers = customerRepository.SearchFor(x => x.CustomerType = "ABC" && x.Age > 21);
The customer entity in this example is just an example. The reason for me to build an sql statement instead of using EF is:
Use Dapper for performance.
I will execute a stored procedure to fetch the reocrds.
The entities I'm using are not mapped to a table. A table exists in the database but these entities are just placeholder POCO's for when retrieving records.
Is it possible?

Take a look at DataContext.GetCommand Method
Per MSDN:
Gets the information about SQL commands generated by LINQ to SQL.
This will get you the whole SQL, but some string manipulation will get you just the Where clause.

I wrote code to convert to SQL.
https://github.com/phnx47/MicroOrm.Dapper.Repositories - Include SqlGenerator
https://github.com/phnx47/MicroOrm.SqlGenerator
Example:
var account = accountsRepository.FindAsync(x => x.Id == id)
Generated:
SELECT Accounts.Id, Accounts.Name, FROM Accounts WHERE Accounts.Id = #Id

Related

Query Syntax not working for multiple objects in linq

I have created my model objects (DTO's) from EF's code first approach from an existing database and table selection. I am able to join multiple tables using method syntax but query syntax's fails to initialize object on the second dbcontext while joining.
I tried to replicate if method syntax works and it does work but query syntax doesn't except the first statement and fetching from single table.
Method syntax
var customers = procontext.Customer
.Join(procontext.ROLODEX, cust => cust.rolodex_sak,
rol => rol.rolodex_sak,
(cust, rol) => new { customerid = cust.customer.code, fname = rol.lname)});
Query Syntax
var customers = from cust in procontext.Customer
join rol in procontext.rolodex on cust.rolodex_sak = rol.
When doing rol and ., it doesn't show any property and when I reverse the line rol fetches all the properties but then cust fails to load customer objects. So only first statement works in query syntax.
My bad I was using "=" instead of equals, it works now.

Using a class in joining to database table with EF

If I have a summary class of some objects I need ( for example its primary key, etc..) is there a way to use a list of that class object when I am writing a joining to other tables? so all the things in my LINQ query are real table like this.Context.MyTable but one of them be my List<MyClass> ?
or is there any LINQ related Nuget project that makes this possible?
The EF LINQ queries aren't actually code that is run in C#, they are converted to SQL and run on the database server; so you can't join them with an in-memory array (or List<T>). What you can do, is use Contains like so:
public IEnumerable<Table1> GetThingsFromDatabse(DataContext db, IList<MyObject> objects)
{
var ids = objects.Select(x => x.Id).ToList();
var results = Enumerable.ToList(
from x in db.Table1s
where ids.Contains(x.Id)
select x
);
return results;
}
This gets translated into SQL that looks like this:
SELECT *
FROM [Table1] x
WHERE x.Id IN (#Id1, #Id2, ...)

filter linq to sql with a entity framework where in

I am doing 2 linq queries one with entity framework and the other is linq to sql and they are not playing well together at all.
The first query grabs id's that are in one table via entity framework.
var pemdata = from pd in db.tblMap
where pd.PID == pid
select new
{
eid = pd.EID
};
And then I'm filtering the second query using a contains via linq to sql.
var data = from e in p.entities
join et in p.entity_types on e.entity_type equals et.entity_types_id
where pemdata.Contains(e.entity_id)
select new gEntities
{
entity_type = e.entity_type.ToString(),
Name = e.entity_name,
Type = et.entity_types_name,
Address = e.entity_address,
City = e.entity_city,
Zip = e.entity_zip.ToString()
};
The issue I'm seeing is an error.
Instance argument: cannot convert from 'System.Linq.IQueryable' to
'System.Linq.ParallelQuery'
'System.Linq.IQueryable' does not contain a definition for 'Contains' and the best extension method overload
'System.Linq.ParallelEnumerable.Contains(System.Linq.ParallelQuery,
TSource)' has some invalid arguments
I usually don't have a problem doing a contains like this. but when I'm mixing linq to sql and entity framework I get this issue.
Any thoughts?
You'll need to materialize the first query before using the results. Easiest way is to just call .ToList() on it. Then you can use the results in the second query.
var pemdata = (from pd in db.tblMap
where pd.PID == pid
select pd.EID).ToList();

How to integrate external list to raw sql query join as table in a linq raw sql query

i have the following query running 10-20 times / page in my project. i have tried to run this query with linq to sql, linq to entities but this is far more faster then them.
The question is if i could pass in the external list(sContentIds) into query with a join statement, would it make the query faster then using SQL IN statement? If so how can i achieve this. sContentIds.Count may vary from 1-40 most of the times.
List<filterContentsPCDTO> cContents = unitOfWork.ExecuteQuery<filterContentsPCDTO>(#"SELECT c.ContentId, c.ContentPageId, c.CreatedById, p.PCA, p.PCC, p.PCD, c.AlbumId, a.AlbumTypeId
FROM Contents c
INNER JOIN Privatizations p ON c.ContentId = p.ContentId
LEFT JOIN Albums a ON c.AlbumId = a.AlbumId
WHERE c.ContentId IN (" + string.Join(",", sContentIds) + ")").ToList();
We are working on ASP.NET MVC4 framework and using unit of work pattern for database interactions. Normally i had built this query like follows but it was 5 times slower then raw sql query.
var cContents = unitOfWork.ContentRepository
.GetFiltered(x => contentIds.Contains(x.ContentId)).Select(x => new filterContentsPCDTO()
{
ContentId = x.ContentId,
ContentPageId = x.ContentPageId,
CreatedById = x.CreatedById,
PCA = x.Privatization.PCA,
PCC = x.Privatization.PCC,
PCD = x.Privatization.PCD,
PrivatizationModifiedById = x.Privatization.ModifiedById,
AlbumId = x.AlbumId,
albumTypeId = x.AlbumId == null ? -1 : x.Album.AlbumTypeId
}).ToList();
Implementation of GetFiltered Method
public IEnumerable<T> GetFiltered(
Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
string includeProperties = "")
{
IQueryable<T> query = _dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query);
}
else
{
return query;
}
}
If you're using SQL Server 2008 (or newer) and increasing performance is the main objective here (and you're maybe willing to abandon LINQ to SQL for this scenario), I would recommend writing this query as a stored procedure that takes a user-defined table type as a parameter. This will allow you to pass your entire sContentIds collection to the database and still benefit from advantages of a stored procedures over an ad-hoc query.
First, define the table type as something like:
CREATE TYPE [dbo].[ContentList] AS TABLE(
[ContentId] [int]
)
Then create the procedure as something like:
CREATE PROCEDURE [dbo].[usp_GetContents]
#contentIds ContentList READONLY
AS
SELECT c.ContentId
,c.ContentPageId
,c.CreatedById
,p.PCA
,p.PCC
,p.PCD
,c.AlbumId
, a.AlbumTypeId
FROM Contents c
INNER JOIN Privatizations p
ON c.ContentId = p.ContentId
LEFT JOIN Albums a
ON c.AlbumId = a.AlbumId
WHERE c.ContentId IN (SELECT ContentId FROM #contentIds)
Then you should be able to call it from C# using the technique described in this answer (basically, create a DataTable from your list then add it like a regular parameter). Unfortunately it looks like this is tough to do with LINQ to SQL, but, as I said, if increasing performance is the main goal, this could be an option.

Linq to Sql Query returning same record twice

I am querying the database using Linq to Sql. Here is my data :
Name LastName Age
------------------------------
1 Abc Def 15
2 Abc Def 17
3 xyz wss 17
My Linq to Sql Code is :
Context _context = new Context("Conn_String");
var table = _context.GetTable<Person>();
List<Person> persons = table.Where<Person>(p => p.Name == "Abc" && p.LastName == "Def").ToList<Person>();
According to my understanding, This query should return 2 records. i.e. Record 1 and Record 2. But it is returning Record 1 twice. Can you enlighten me if it is a bug in Linq to Sql or something I am doing wrong?
EDIT:
This is my DAL Code:
public List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T : class
{
try
{
Context _context = new Context("Conn_String");
var table = _context.GetTable<T>();
return table.Where<T>(predicate).ToList<T>();
}
catch (Exception ex)
{
throw ex;
}
}
I am calling this method as :
List<Person> person = DAL.GetList<Person>(p => p.Name == "Abc" && p.LastName == "Def");
foreach(var Person in persons )
{
// Print(person.Age);
}
I've just run into this issue myself.
Check which property the model has inferred to be your entity key for your Person class.
If it has a non-unique column as the entity key it will will use the first row which matches the value for each row when converting using ToList()
Short answer, You need to add the Primary key in the data your fetching.
You can simply add a column to your view select statement which is unique. You don’t have to use that column in your program but it will allow EF to properly build each object for you.
Although the question was asked in Nov 2012 and I am answering in Jul 2019. But the detailed answer is available at the below source.
I am answering maybe thing might help someone out there.
LINQ in .NET returning duplicate rows from a working SQL view
https://www.itworld.com/article/2833108/linq-in--net-returning-duplicate-rows-from-a-working-sql-view--solved-.html
Hi Usman,
This is my table :
Here i am using the following query :
using (DataClassesDataContext dc = new DataClassesDataContext())
{
var v = (from c in dc.t_controls where (c.config_display == "SHOW_VA" && c.next_value == 1) select c.description).ToList();
}
This query returns all the 5 rows.Take it as reference and check where are you wrong.Hope it help you.
Can you run your query and profile it using SQL Server profiler (assuming SQL Server) in the database. I am wondering if you have duplicate records in your table..or if there is a join causing duplicates.
I have used LINQ to SQL with no problems.
If the database profile comes out correct and you want to "force it" to be unique you can always pass a distinct method in your LINQ query at the end.

Categories