Seeing the SQL that LINQ generates [duplicate] - c#

This question already has answers here:
Get SQL query from LINQ to SQL?
(4 answers)
Closed 7 years ago.
If I have a LINQ to SQL statement for example
var query = (from a in this.Context.Apples select a.Name).ToList();
When I want to see what SQL is being generated by LINQ, what I do is that I comment out the ToList() and put a breakpoint on the command after this LINQ statement and then I can hover it and read the SQL.
My question: Is that a correct way of getting the generated SQL?

You can also set the Log property of Your context to :
public class MyContext : DbContext{
MyContext(){
Database.Log = Console.WriteLine;
//or like this
//Database.Log = message => Trace.TraceInformation(message);
}
}

Yes, that's a correct way, but of course, there are others:
var context = new DataClasses1DataContext();
var sb = new StringWriter();
context.Log = sb;
var query = (from a in context.Persons select a.Name);
string s = query.ToString();
string command = context.GetCommand(query).CommandText;
//The log requires the query to actually hit the database
query.ToList();
string log = sb.ToString();
And also Linqpad:

You can also use SQL Server Profiler, add a trace, and see generated queries as they are being executed by the server.

Related

How can I map a "select all" query with 2 tables using SqlQuery

I'm trying to retrieve all fields from two joined tables to any kind of a c# object.
So I'm trying to run this code:
var query = #$"EXEC('select *
from persons p join students s on p.id=s.id
where p.id = 21')";
var result = _context.Database.SqlQuery<?>(query).ToList();
But I don't get what should be instead of the question mark.
I've tried List<object> and Dictionary<string,string> but since I couldn't get exactly how this is being mapped, I don't understand to what it can be mapped.
There is a somewhat similar question here but its solution only addresses two columns, and it apparently doesn't support returning nulls.
You can try creating a stored procedure or a function in the SQL level.
Then, just select then generated table / result.
So, you already have an idea of what class it is.
I frequently use the dynamic type like this :
var lst = _context.Database.SqlQuery<dynamic>(query).ToList();
foreach (var item in lst)
{
var myVar = item.myfieldName;
}
It may be preferable to name each field in your query instead of using select *.

Multiple SQL query in C# [duplicate]

This question already has answers here:
How to run multiple SQL commands in a single SQL connection?
(9 answers)
How do I return multiple result sets with SqlCommand?
(7 answers)
Closed 5 years ago.
I'm having trouble to figure out how to get more then one SQL query to work in C#. I have something like this:
breakControlq.CommandText =
#"SELECT something as q1 From table" +
"SELECT somethingelse as q2 FROM table where this = this";
breakControlq.CommandType = CommandType.Text;
breakControlq.Connection = hd01Connect;
try
{
hd01Connect.Open();
breakControlRead = breakControlq.ExecuteReader();
while (breakControlRead.Read())
{
textBox1.AppendText(breakControlRead["q1"].ToString());
textBox2.AppendText(breakControlRead["q2"].ToString());
}
catch(System.Data.SqlClient.SqlException ex)
{
MessageBox.Show(ex.Message, "Connection Error");
}
Is this possible to do?
Do I have to repeat the connection/command to every single query?
I'm pretty new at this and some of you will tell that this has already been answered somewhere, but I searched so many posts that I'm more confused then when a started to search for the solution.
You are looking for .NextResult(). The .Read() method changes to the next row in the current grid; .NextResult() moves to the next grid:
while (breakControlRead.Read())
{
// process rows from first grid
}
if(breakControlRead.NextResult()) {
while (breakControlRead.Read())
{
// process rows from second grid
}
}
Alternatively; "dapper" would expose this via .QueryMultiple():
using(var multi = conn.QueryMultiple(sql, args)) {
var s = multi.Read<string>().AsList(); // items from first grid
var i = multi.ReadSingle<int>(); // items from second grid
// ...
}
Note! You do need to ensure that your two queries are separated by either whitespace or ;; in your case this would be fine:
#"SELECT something as q1 From table
SELECT somethingelse as q2 FROM table where this = this";
(note whitespace)
alternative and more correctly:
#"SELECT something as q1 From table;
SELECT somethingelse as q2 FROM table where this = this;";
or:
#"SELECT something as q1 From table;SELECT somethingelse as q2 FROM table where this = this;";
I'm having trouble to figure out how to get more then one SQL query to
work in C#
Well, wrap both your SQL statement in a stored procedure and call that procedure from your application code like
create procedure usp_data
as
begin
SELECT something as q1 From table;
SELECT somethingelse as q2 FROM table where this = this;
end
See How to: Execute a Stored Procedure that Returns Rows for more information

Optimize LINQ query that runs fast in Sql server?

I want to calculate the rows of a related table:
MainTable tbl = tblInfo(id);
var count = tbl.Related_Huge_Table_Data.Count();
The problem is: this takes too long (about 20 seconds) to execute, although when I run this query in Sql Server it executes below one second. How can I optimize this query in linq? I also tried to use stored procedure but no luck.
This is the tblInfo method:
public MainTable tblInfo(int id)
{
MyDataContext context = new MyDataContext();
MainTable mt = (from c in context.MainTables
where c.Id == id
select c).SingleOrDefault();
return mt;
}
I used LinqToSql and classes was generated by LinqToSql.
By running SingleOrDefault() you execute the query and have to deal with results in memory after that. You need to stay with IQueryable until your query is fully constructed.
The easiest way to answer "how many child records this parent record has" is to approach it from the child side:
using (var dx = new MyDataContext())
{
// If you have an association between the tables defined in the context
int count = dx.Related_Huge_Table_Datas.Where(t => t.MainTable.id == 42).Count();
// If you don't
int count = dx.Related_Huge_Table_Datas.Where(t => t.parent_id == 42).Count();
}
If you insist on the parent side approach, you can do that too:
using (var dx = new MyDataContext())
{
int count = dx.MainTables.Where(t => t.id == 42).SelectMany(t => t.Related_Huge_Table_Datas).Count();
}
If you want to keep a part of this query in a function like tblInfo, you can, but you can't instantiate MyDataContext from inside such function, otherwise you will get an exception when trying to use the query with another instance of MyDataContext. So either pass MyDataContext to tblInfo or make tblInfo a member of partial class MyDataContext:
public static IQueryable<MainTable> tblInfo(MyDataContext dx, int id)
{
return dx.MainTables.Where(t => t.id == id);
}
...
using (var dx = new MyDataContext())
{
int count = tblInfo(dx, 42).SelectMany(t => t.Related_Huge_Table_Datas).Count();
}
Try this
MyDataContext context = new MyDataContext();
var count=context.Related_Huge_Table_Data.where(o=>o.Parentid==id).Count();
//or
int count=context.Database.SqlQuery<int>("select count(1) from Related_Huge_Table_Data where Parentid="+id).FirstOrDefault();
If you wish to take full advantage of your SQL Database's performance, it may make sense to query it directly rather than use Linq. Should be reasonably more performent :)
var Related_Huge_Table_Data = "TABLENAME";//Input table name here
var Id = "ID"; //Input Id name here
var connectionString = "user id=USERNAME; password=PASSWORD server=SERVERNAME; Trusted_Connection=YESORNO; database=DATABASE; connection timeout=30";
SqlCommand sCommand = new SqlCommand();
sCommand.Connection = new SqlConnection(connectionString);
sCommand.CommandType = CommandType.Text;
sCommand.CommandText = $"COUNT(*) FROM {Related_Huge_Table_Name} WHERE Id={ID}";
sCommand.Connection.Open();
SqlDataReader reader = sCommand.ExecuteReader();
var count = 0;
if (reader.HasRows)
{
reader.Read();
count = reader.GetInt32(0);
}
else
{
Debug.WriteLine("Related_Huge_Table_Data: No Rows returned in Query.");
}
sCommand.Connection.Close();
Try this:
MyDataContext context = new MyDataContext();
var count = context.MainTables.GroupBy(x => x.ID).Distict().Count();
The answer of GSerg is the correct one in many case. But when your table starts to be really huge, even a Count(1) directly in SQL Server is slow.
The best way you can get round this is to query the database stats directly, which is impossible with Linq (or I don't know of).
The best thing you can do is to create a static sub (C#) on your tables definition witch will return the result of the following query:
SELECT
SUM(st.row_count)
FROM
sys.dm_db_partition_stats st
WHERE
object_name(object_id) = '{TableName}'
AND (index_id < 2)
where {TableName} is the database name of your table.
Beware it's an answer only for the case of counting all records in a table!
Is your linq2sql returning the recordset and then doing the .Count() locally, or is it sending SQL to the server to do the count on the server? There will be a big difference in performance there.
Also, have you inspected the SQL that's being generated when you execute the query? From memory, Linq2Sql allows you to inspect SQL (maybe by setting up a logger on your class?). In Entity Framework, you can see it when debugging and inspecting the IQueryable<> object, not sure if there's an equivalent in Linq2Sql.
Way to view SQL executed by LINQ in Visual Studio?
Alternatively, use the SQL Server Profiler (if available), or somehow see what's being executed.
You may try following:-
var c = from rt in context.Related_Huge_Table_Data
join t in context.MainTables
on rt.MainTableId ==t.id where t.id=id
select new {rt.id};
var count=c.Distict().Count();

Linq performance with subqueries and LET

I have a query I'm executing in LinqPad (EF4 against a SQL2010 backend), which uses navigation properties to access related tables. I don't really have access to fiddle with indexes and so forth, and was wondering if there are any ways to avoid all the subqueries inherent in those 'firstordefault' items toward the bottom of the query. I've tried using a 'let' statement at the top as in "let accounts = i.ExpenseItemAccountings.FirstOrDefault()" and then use that reference to make it run only one subquery, but it still takes easily more than an hour to run this query for any meaningful number of records.
Is there any way I can make this more efficient?
var output = from i in ExpenseItems where
i.Er_Approved_Date >= fromDate &&
i.Er_Approved_Date <= toDate
select new {ER_Num = i.ErNum,
Line_Num = i.ItemNum,
Report_Title = i.Report_Title,
Requestor = i.Requester_Name,
Preparer = i.Preparer_Name,
ER_Total_Value = i.Er_TotalVal,
Partition = i.Org,
Transaction_Date = i.Item_Transaction_Date,
Approved_Date = i.Er_Approved_Date,
Item_Amount = i.Item_Amount,
Tips = i.Item_Tips,
GST = i.Item_Gst,
Have_Receipt = i.Item_Have_ReceiptTf,
Have_Invoice = i.Item_Have_InvoiceTf,
Vendor = i.Item_Vendor,
City = i.Item_City,
Item_Expense_Type = i.Item_Expense_Type,
Item_Description = i.Item_Expense_Description,
Misc_Item_Commodity = i.Item_Misc_Commodity_Name,
Misc_Item_SubCategory = i.Item_Misc_Specify,
Misc_Item_OtherMisc_Description = i.Item_Misc_Specify_Other_Desc,
Entity_Num = i.ExpenseItemAccountings.FirstOrDefault().Item_Entity_Num,
Entity_Name = i.ExpenseItemAccountings.FirstOrDefault().Item_Entity_Name,
Account_Num = i.ExpenseItemAccountings.FirstOrDefault().Item_Account_Num,
Account_Desc = i.ExpenseItemAccountings.FirstOrDefault().Item_Account_Name,
SubAccount_Num = i.ExpenseItemAccountings.FirstOrDefault().Item_SubAccount_Num,
SubAccount_Name = i.ExpenseItemAccountings.FirstOrDefault().Item_SubAccount_Name,
CostCentre_Num = i.ExpenseItemAccountings.FirstOrDefault().Item_CostCentre_Num,
CostCentre_Name = i.ExpenseItemAccountings.FirstOrDefault().Item_CostCentre_Name,
Project_Code = i.ExpenseItemAccountings.FirstOrDefault().Expense_Item_ProjectCode,
////Percent_Allocated = i.ExpenseItemAccountings.FirstOrDefault().Item_Percent,
ER_Comments = i.Er_Comments,
Item_First_Comment = i.ExpenseItemComments.FirstOrDefault().Comment_Content,
Violations = i.ExpenseItemViolations.Count()
};
On LinqPad you should be able to view the SQL statement generated from the LINQ statement.
In my opinion there is always a debate between using let or navigation properties in LINQ to Entities (or LINQ to SQL). Sometimes a simple JOIN might work better too. In other words it all depends on how your LINQ provider (Entity Framework) optimizes your specific query into SQL statements.
I would suggest you test your query with all let/join/navigation to see the generated SQL statement.
You can use ObjectQuery under System.Data.Objects in your code to view realtime SQL statement in case you don't have SQL profiler or intellitrace tool:
((ObjectQuery)anyLinqQuery).ToTraceString();
Also you can try using multiple from clause:
var output = from i in ExpenseItems
from exp in i.ExpenseItemAccountings
where ....
select new {...};
or
var output = from i in ExpenseItems
from exp in i.ExpenseItemAccountings.DefaultIfEmpty()
where ....
select new {...};

Get used tables from sql query [duplicate]

This question already has answers here:
List of tables used in an SQL Query
(5 answers)
Closed 9 years ago.
I need extract from simple string that represent an sql query the tables that are used on the query without execute the query itself in C#.
Example:
string strQuery = "SELECT * FROM table1 LEFT JOIN (SELECT * FROM table2) tt WHERE tt.name IN (SELECT name FROM table3)";
ArrayList arrUsedTables = GetUsedTablesFromQuery(strQuery);
and after this line the object arrUsedTables would contain:
table1,table2,table3
Remember that the query may be much complicated!
Without going to the DB you can't know for certain the names of the tables used in the query.
What if your query uses a view or a stored procedure?
Without consulting the database, these are transparent to the consumer.
The only way to be certain is to query the list of the tables from the database and then to attempt to parse them from your inline sql.
You will have to add references and directives for the following assemblies:
using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;
using System.IO;
Then, you may create the GetUsedTablesFromQuery method:
private static ArrayList GetUsedTablesFromQuery(string strQuery)
{
var parser = new TSql100Parser(true);
IList<ParseError> errors = new List<ParseError>();
using (TextReader r = new StringReader(strQuery))
{
var result = parser.GetTokenStream(r, out errors);
var tables = result
.Select((i, index) => (i.TokenType == TSqlTokenType.From) ? result[index + 2].Text : null)
.Where(i => i != null)
.ToArray();
return new ArrayList(tables);
}
}
You can certainly use a SQL parser such as ANTLR, as described in this question and answer, in order to get a full parse of the SQL, and then extract the table names.
Another option is to execute some raw SQL to get the execution plan of the query (using the instructions here). The execution plan is in XML, and then you can use Linq to XML to query the plan for all Table attributes on any ColumnReference tag.

Categories