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.
Related
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
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?
Is there a way to get the column names that an arbitrary query will return using just T-SQL that works with pre-2012 versions of Microsoft SQL Server?
What Doesn't Work:
sys.columns and INFORMATION_SCHEMA.COLUMNS work great for obtaining the column list for tables or views but don't work with arbitrary queries.
sys.dm_exec_describe_first_result would be perfect except that this management function was added in SQL Server 2012. What I'm writing needs to be backwards compatible to SQL Server 2005.
A custom CLR function could easily provide this information but introduces deployment complexities on the server side. I'd rather not go this route.
Any ideas?
So long as the arbitrary query qualifies to be used as a nested query (i.e. no CTEs, unique column names, etc.), this can be achieved by loading the query's metadata into a temp table, then retrieving column details via sys.tables:
SELECT TOP 0 * INTO #t FROM (query goes here) q
SELECT name FROM tempdb.sys.columns WHERE object_id = OBJECT_ID('tempdb..#t')
DROP TABLE #t
Thanks to #MartinSmith's for suggesting this approach!
I'm trying to construct a T-SQL statement with a WHERE clause determined by an input parameter. Something like:
SELECT * FROM table
WHERE id IN
CASE WHEN #param THEN
(1,2,4,5,8)
ELSE
(9,7,3)
END
I've tried all combination of moving the IN, CASE etc around that I can think of. Is this (or something like it) possible?
try this:
SELECT * FROM table
WHERE (#param='??' AND id IN (1,2,4,5,8))
OR (#param!='??' AND id in (9,7,3))
this will have a problem using an index.
The key with a dynamic search conditions is to make sure an index is used, instead of how can I easily reuse code, eliminate duplications in a query, or try to do everything with the same query. Here is a very comprehensive article on how to handle this topic:
Dynamic Search Conditions in T-SQL by Erland Sommarskog
It covers all the issues and methods of trying to write queries with multiple optional search conditions. This main thing you need to be concerned with is not the duplication of code, but the use of an index. If your query fails to use an index, it will preform poorly. There are several techniques that can be used, which may or may not allow an index to be used.
here is the table of contents:
Introduction
The Case Study: Searching Orders
The Northgale Database
Dynamic SQL
Introduction
Using sp_executesql
Using the CLR
Using EXEC()
When Caching Is Not Really What You Want
Static SQL
Introduction
x = #x OR #x IS NULL
Using IF statements
Umachandar's Bag of Tricks
Using Temp Tables
x = #x AND #x IS NOT NULL
Handling Complex Conditions
Hybrid Solutions – Using both Static and Dynamic SQL
Using Views
Using Inline Table Functions
Conclusion
Feedback and Acknowledgements
Revision History
if you are on the proper version of SQL Server 2008, there is an additional technique that can be used, see: Dynamic Search Conditions in T-SQL Version for SQL 2008 (SP1 CU5 and later)
If you are on that proper release of SQL Server 2008, you can just add OPTION (RECOMPILE) to the query and the local variable's value at run time is used for the optimizations.
Consider this, OPTION (RECOMPILE) will take this code (where no index can be used with this mess of ORs):
WHERE
(#search1 IS NULL or Column1=#Search1)
AND (#search2 IS NULL or Column2=#Search2)
AND (#search3 IS NULL or Column3=#Search3)
and optimize it at run time to be (provided that only #Search2 was passed in with a value):
WHERE
Column2=#Search2
and an index can be used (if you have one defined on Column2)
if #param = 'whatever'
select * from tbl where id in (1,2,4,5,8)
else
select * from tbl where id in (9,7,3)