I am building an IQueryable<int> and depending on what criteria the user selects, the alias of the int column in the generated SQL may vary. Sometimes it's the name of the column and sometimes it's something like "C1". Similar to my question here where I ask How can I get the parameters of an Entity Framework query?, I am wondering if there's a way to get the generated alias name of the query?
This doesn't directly answer my original question, but I just learned of an awesome trick that allows me to override what the alias would be (in SQL Server) and I had to share it.
var query = myIQueryable.ToString();
var sql = $#"SELECT x.myAlias
FROM ({query}) x(myAlias)";
Now I can combine my super-complex IQueryable with this little snippet of SQL to do bulk insert and update operations. Such as:
var query = myIQueryable.ToString();
var sql = $#"INSERT INTO dbo.myTable (col1)
SELECT x.myAlias
FROM ({query}) x(myAlias)";
Or
var query = myIQueryable.ToString();
var sql = $#"UPDATE dbo.myTable
SET Col1 = 1
FROM dbo.myTable
JOIN ({query}) x(myAlias) ON x.myAlias = dbo.myTable.SomeColumn";
Of course, you still have to plug in the parameters of the query, which you can get by following the example given on my previous question: How can I get the parameters of an Entity Framework query?
Related
I have a scenario where I need to create raw query towards CosmosDb. For the sake of this question, I have a simplified call:
CosmosQueryableExtensions.FromSqlRaw(db.ProjectFolders, "SELECT VALUE c FROM c WHERE c.Site = \"mysite\"")
but it generates query with undesired subquery:
info: Microsoft.EntityFrameworkCore.Database.Command[30102]
Executed ReadNext (784.3342 ms, 2.85 RU) ActivityId='3f8b0dfd-09f5-4fd3-99e3-3bae8edbe06e', Container='Items', Partition='?', Parameters=[]
SELECT c
FROM (
SELECT VALUE c FROM c WHERE c.Site = "mysite"
) c
Is this by design, irrelevant, or am I doing something wrong?
Explaination :- FromSQLRow generates query with in subquery and its by design.
Composing query with LINQ, EF Core will consider passed LINQ SQL query as subquery over the database. Composing SQL query with in LINQ starts with SELECT but can't have SQL like features such as
Trailing semicolon (;)
ORDER BY clause
References :-
https://learn.microsoft.com/en-us/ef/core/querying/sql-queries#composing-with-linq
Include with FromSqlRaw and stored procedure in EF Core 3.1
How do I access the VALUE using CosmosQueryableExtensions
I'm using a PostgreSQL with a Go driver. Sometimes I need to query not existing fields, just to check - maybe something exists in a DB. Before querying I can't tell whether that field exists. Example:
where size=10 or length=10
By default I get an error column "length" does not exist, however, the size column could exist and I could get some results.
Is it possible to handle such cases to return what is possible?
EDIT:
Yes, I could get all the existing columns first. But the initial queries can be rather complex and not created by me directly, I can only modify them.
That means the query can be simple like the previous example and can be much more complex like this:
WHERE size=10 OR (length=10 AND n='example') OR (c BETWEEN 1 and 5 AND p='Mars')
If missing columns are length and c - does that mean I have to parse the SQL, split it by OR (or other operators), check every part of the query, then remove any part with missing columns - and in the end to generate a new SQL query?
Any easier way?
I would try to check within information schema first
"select column_name from INFORMATION_SCHEMA.COLUMNS where table_name ='table_name';"
And then based on result do query
Why don't you get a list of columns that are in the table first? Like this
select column_name
from information_schema.columns
where table_name = 'table_name' and (column_name = 'size' or column_name = 'length');
The result will be the columns that exist.
There is no way to do what you want, except for constructing an SQL string from the list of available columns, which can be got by querying information_schema.columns.
SQL statements are parsed before they are executed, and there is no conditional compilation or no short-circuiting, so you get an error if a non-existing column is referenced.
My trivial problem is this: I need to select a single field from a table filtering by the Id field.
Something that in SQL I would simply write like this:
SELECT Field FROM {Table} WHERE Id = 1
The table name is variable.
How do I do this very trivial Query with EF Core 3.1 considering that the table name can vary?
I have already tried
context.Database.ExecuteSqlCommand($"SELECT TOP 1 Field FROM {table} WHERE Id={id}")
but I cannot read the result (it always returns -1)
I also tried this:
var test = context.Set<T>()
.FromSqlRaw($"SELECT Id FROM {table}")
.FirstOrDefault();
but give me an error because it wants all the fields in the select statement
Thanks for the support
Suppose the server side code is something like that:
String id = getIdFromHttpRequest();
String value = getValueFromHttpRequest();
ResultSet rs = new ResultSet();
String query = "INSERT INTO users VALUES ('" + id + "', '" + value + "');"
rs = SQL.doQuery(query); // i know it's not the syntax, but the point is clear
Well, the injection is easy, I can make it execute an SQL command, but the problem is I want to see the result set (I inject SELECT command).
Is there a way of doing so?
You probably cannot achieve this.
As you know, an INSERT statement has no result set, even if you use SQL injection. At best, you could make it execute a SELECT as a scalar subquery. It's not hard to spoof your example to execute the following:
INSERT INTO users VALUES ('8675309', '' || (SELECT ...blah blah...) || '');
But that still would not return a result set, because INSERT never has a result set.
You would need to execute a second query to do that. Some query interfaces do support multi-query in a single call to doQuery(), but this is not always true (depends on the brand of database you use, and possibly some configuration options).
INSERT INTO users VALUES (...whatever...);
SELECT * FROM secure_table WHERE (id = '8675309');
With SQL injection, you can manipulate the SQL, but you can't manipulate the rest of the code in the application that runs the SQL. In the example you show, the app is designed to run an INSERT query, not an INSERT followed by a SELECT. The app would have no reason to fetch a result set after executing an INSERT.
It's hard to imagine how you could use SQL injection alone to trick the code you show into fetching and displaying a result set.
I don't think it is possible to use SQL injection do read data by exploiting a non-reading query.
I am using EF Core 1.1 and have a query like
var list=from l in context.Users
where l.SomeProp==someVal
select l;
I have a UDF which returns a table of Id's and I basically want to generate the following query:
select * from Users where SomeProp=#someVal and SomeId in (select id from fn_myfunc(#id))
Is this possible to do?
I think you are limited to running a raw SQL query against the database to be able to use a table valued function. For example:
var query = #"SELECT * FROM Users WHERE SomeProp = {0}
AND SomeId IN (SELECT id FROM fn_myfunc({1})";
var users = context.Users
.FromSql(query, someProp, someId)
.ToList();
There are some limitations with this method. From the docs:
SQL queries can only be used to return entity types that are part of your model. There is an enhancement on our backlog to enable returning ad-hoc types from raw SQL queries.
The SQL query must return data for all properties of the entity type.
The column names in the result set must match the column names that properties are mapped to. Note this is different from EF6.x where property/column mapping was ignored for raw SQL queries and result set column names had to match the property names.
The SQL query cannot contain related data. However, in many cases you can compose on top of the query using the Include operator to return related data.
You can return related data (i.e. Include) like this:
var users = context.Users
.FromSql(query, someProp, someId)
.Include(u => u.OtherThings)
.ToList();
If you need to do anything more complex, then you would need to either drop down to using raw data access (like ADO.Net) or another ORM. I know people who use EF Core for the bulk of the work and then occasionally drop into Dapper for performance or raw SQL that doesn't suit EF.