How can I directly execute SQL queries in linq - c#

In C# with VS 2008,I have a query ,In this query i join more than one tables,so i don't know the type , I want to know how to directly run a sql query in linq .
IEnumerable<Type> results = db.ExecuteQuery<TYpe>("sql query")
My above query works fine but I want to avoid type, I want to write
var results = db.ExecuteQuery("sql query");
Is there any way to write it?
Thanks in advance.

var result = dataContext.ExecuteQuery<JobsDto>
("Select JobID,JobName From jobs");
but make sure JobsDto has two properties JobID and JobName and there types the same type as the table columns
PS. DTO stand for Data Transfer Object

You need to specify the type to map to from the query results. You can use a System.Type object instead of statically specifying it as a generic type parameter:
var results = db.ExecuteQuery(typeof(Customer), "sql query ");
If you just want a plain ADO.NET DataReader you could use the DataContext.Connection property:
using (var cmd = db.Connection.CreateCommand())
{
cmd.CommandText = "sql query ";
var results = cmd.ExecuteReader();
}

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 *.

Querying with a string converted from an array of ints, results in Conversion data type smallint error

I have an array of ints, each int corresponds to an phone ID number in the database.
In my application I convert the array of ints into a string as seen below and use this as an sql parameter.
public IList<Phones> GetPhonesByID(int[] idNumbersInts)
{
var idNumbersStr = string.Join(",", idNumbersInts);
var phones = _context.Database.SqlQuery<Phones>(#"
SELECT Make,
Model
FROM PHONES
WHERE ID_NUM IN (#idNumbers)",
new SqlParameter("#idNumbers", idNumbersStr),
).ToList();
return phones;
}
This results in the error
Conversion failed when converting the varchar value '#idNumbers' to data type smallint
The challenge I have is that I am working with a legacy database so the fix has to be done entirely in my code and not on the db end.
SQL parameters simply don't work like that. SQL parameters are there to help you avoid SQL injections, but you are trying to do exactly that: Inject SQL with your string of comma separated integers. Database engine is trying to convert your full varchar (string) type parameter value into smallint. It doesn't know nor care that you are trying to give it a list.
Now, with integers as parameters to your method you are quite safe to inject those into your SQL straight up.
string sqlQuery = String.Format(#"SELECT Make, Model
FROM PHONES WHERE ID_NUM IN ({0})", idNumberStr);
var phones = _context.Database.SqlQuery<Phones>(sqlQuery).ToList();
If in some other query you are not using integers but strings, then this approach is a security risk. In that case this next approach is better and it could be use in your current case, too. Be wary that if your list of items grows large, you should consider writing them in a temporary table first and use that in your WHERE clause, so that the database engine doesn't suffocate while trying to parse your list.
var sqlParams = list<SqlParameter>();
int index = 0;
foreach (var id in idNumbersInts)
sqlParams.Add(new SqlParameter("#p" + (index++), id));
string sqlQuery = String.Format(#"SELECT Make, Model
FROM PHONES WHERE ID_NUM IN ({0})",
String.Join(",", sqlParams.Select(p => p.ParameterName).ToArray()));
var phones = _context.Database.SqlQuery<Phones>(sqlQuery,
sqlParams.ToArray()).ToList();
I think you don't need execute sql, try this:
var phones = _context.Phones.Where(ph => idNumbersInts.Contains(ph.ID_NUM));

How to select varying amount of columns with ExecuteStoreQuery

I'm dynamically building a select query with a varying number of columns.
select
a as col0,
b as col1,
...,
c as coln
...
The query is supposed to retrieve a matrix of integers.
When executing the query with ObjectContext.ExecuteStoreQuery, I get the right amount of lines but each line seems to be empty.
Here is my code:
var lines = context.ExecuteStoreQuery<List<int>>(queryString).AsEnumerable()
How could I make it work?
I found here that I should be using ADO.NET for this kind of things.
Unfortunately Entity Framework 6 does not have a lot of flexibility in the internal mapping code, so it is not able to map the SQL result to your List<int> or to any other collection of primitive types.
To understand why it is not able to do it, you need to know that internally EF6 uses a DbDataReader to read the SQL results, then it builds a ColumnMap from the expected generic result type (in your case the type is a generic List), and it performs a dynamic translation of the SQL results to a result object using the ColumnMap to know what column to map to what property of the object.
Per my explanation above, EF6 ExecuteStoreQuery method is trying to map your columns ("a", "b"..etc.) to the List object properties, and since there are no properties on the List class that match your SQL result column names it is not able to map it.
These limitations make ADO.NET one of the simplest option for dynamic columns. You can use a DbDataReader like in the following code:
var arr = new List<int>();
using (var md = new Context())
{
var conn = md.Database.Connection;
conn.Open();
using (IDbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "select Col1,Col2 from Entities";
using (var reader = (DbDataReader)cmd.ExecuteReader())
{
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
arr.Add(reader.GetInt32(i));
}
}
}
}
}

Convert C# SQL Loop to Linq

I have a list Called ListTypes that holds 10 types of products. Below the store procedure loops and gets every record with the product that is looping and it stores it in the list ListIds. This is killing my sql box since I have over 200 users executing this constantly all day.
I know is not a good architecture to loop a sql statement, but this the only way I made it work. Any ideas how I can make this without looping? Maybe a Linq statement, I never used Linq with this magnitude. Thank you.
protected void GetIds(string Type, string Sub)
{
LinkedIds.Clear();
using (SqlConnection cs = new SqlConnection(connstr))
{
for (int x = 0; x < ListTypes.Count; x++)
{
cs.Open();
SqlCommand select = new SqlCommand("spUI_LinkedIds", cs);
select.CommandType = System.Data.CommandType.StoredProcedure;
select.Parameters.AddWithValue("#Type", Type);
select.Parameters.AddWithValue("#Sub", Sub);
select.Parameters.AddWithValue("#TransId", ListTypes[x]);
SqlDataReader dr = select.ExecuteReader();
while (dr.Read())
{
ListIds.Add(Convert.ToInt32(dr["LinkedId"]));
}
cs.Close();
}
}
}
Not a full answer, but this wouldn't fit in a comment. You can at least update your existing code to be more efficient like this:
protected List<int> GetIds(string Type, string Sub, IEnumerable<int> types)
{
var result = new List<int>();
using (SqlConnection cs = new SqlConnection(connstr))
using (SqlCommand select = new SqlCommand("spUI_LinkedIds", cs))
{
select.CommandType = System.Data.CommandType.StoredProcedure;
//Don't use AddWithValue! Be explicit about your DB types
// I had to guess here. Replace with the actual types from your database
select.Parameters.Add("#Type", SqlDBType.VarChar, 10).Value = Type;
select.Parameters.Add("#Sub", SqlDbType.VarChar, 10).Value = Sub;
var TransID = select.Parameters.Add("#TransId", SqlDbType.Int);
cs.Open();
foreach(int type in types)
{
TransID.Value = type;
SqlDataReader dr = select.ExecuteReader();
while (dr.Read())
{
result.Add((int)dr["LinkedId"]);
}
}
}
return result;
}
Note that this way you only open and close the connection once. Normally in ADO.Net it's better to use a new connection and re-open it for each query. The exception is in a tight loop like this. Also, the only thing that changes inside the loop this way is the one parameter value. Finally, it's better to design methods that don't rely on other class state. This method no longer needs to know about the ListTypes and ListIds class variables, which makes it possible to (among other things) do better unit testing on the method.
Again, this isn't a full answer; it's just an incremental improvement. What you really need to do is write another stored procedure that accepts a table valued parameter, and build on the query from your existing stored procedure to JOIN with the table valued parameter, so that all of this will fit into a single SQL statement. But until you share your stored procedure code, this is about as much help as I can give you.
Besides the improvements others wrote.
You could insert your ID's into a temp table and then make one
SELECT * from WhatEverTable WHERE transid in (select transid from #tempTable)
On a MSSQL this works really fast.
When you're not using a MSSQL it could be possible that one great SQL-Select with joins is faster than a SELECT IN. You have to test these cases by your own on your DBMS.
According to your comment:
The idea is lets say I have a table and I have to get all records from the table that has this 10 types of products. How can I get all of this products? But this number is dynamic.
So... why use a stored procedure at all? Why not query the table?
//If [Type] and [Sub] arguments are external inputs - as in, they come from a user request or something - they should be sanitized. (remove or escape '\' and apostrophe signs)
//create connection
string queryTmpl = "SELECT LinkedId FROM [yourTable] WHERE [TYPE] = '{0}' AND [SUB] = '{1}' AND [TRANSID] IN ({2})";
string query = string.Format(queryTmpl, Type, Sub, string.Join(", ", ListTypes);
SqlCommand select = new SqlCommand(query, cs);
//and so forth
To use Linq-to-SQL you would need to map the table to a class. This would make the query simpler to perform.

statement for npgsql using parameter

I pass the parameters in the sql query using the driver npgsql:
SqlCommand = new NpgsqlCommand();
....
SqlCommand.CommandText = "SELECT id,name FROM table1 WHERE field1=:param2 ORDER BY name;";
SqlCommand.Parameters.AddWithValue("param2", 1);
This query executed correctly and issued the necessary data, but as soon as I add parameter to the sql in the section "select"
SqlCommand.CommandText = "SELECT id,name :param1 FROM table1 WHERE field1=:param2 ORDER BY name;";
SqlCommand.Parameters.AddWithValue("param1", ",field1");
SqlCommand.Parameters.AddWithValue("param2", 1);
it gives me some kind of nonsense. In theory this request to the server is to be treated as
SELECT id,name,field1 FROM table1 WHERE field1=1 ORDER BY name;
but it did not happen.
This raises the question: is there a way to dynamically insert a list of fields using suchlike parameters?
Unfortunately, Npgsql doesn't have support for what you are trying to do. NpgsqlParameter values are supposed to be only used as parameter values in the where clause.
In order to add field names dynamically as you intend, you will have to create the query manually by using string concatenation.
I hope it helps.
Rewrite you CommandText and add this:
foreach (NpgsqlParameter item in _Command.Parameters)
{
comm.Parameters.AddWithValue(item.ParameterName, item.Value);
}
And solve your problem..

Categories