What's the difference between:
DB::table('some_table')
->selectRaw('COUNT(*) AS result')
->get();
and:
DB::select(DB::raw("
SELECT COUNT(*) AS result
FROM some_table"));
In the documentation https://laravel.com/docs/5.6/queries they advert about using raw()due SQL Injection, but it's the same with selectRaw?
The end result of both is the same i.e but there are some difference:
The first one:
DB::table('some_table')
->selectRaw('COUNT(*) AS result')
->get();
Returns a collection of PHP objects,
You can call collections method fluently on the result
It is cleaner.
While the second:
DB::select(DB::raw("
SELECT COUNT(*) AS result
FROM some_table"
));
Returns an array of Php object.
Although they have similarities: the raw query string.
Those two examples yield the same result, although with different result data types.
Using raw queries can indeed be an attack vector if you don't escape values used within the query (especially those coming from user input).
However that can be mitigated very easily by using bindings passed as the second parameter of any raw query method, as showcased in the same documentation (selectRaw accepts a second parameter as an array of bindings, as well as other raw methods from the Query Builder such as whereRaw, etc). Actually at the begining of the docs page you referenced, the second paragraph also states the following:
The Laravel query builder uses PDO parameter binding to protect your application against SQL injection attacks. There is no need to clean strings being passed as bindings.
So as long as you're careful and make sure any parameters are passed as bindings and not concatenated as plain values within the raw query string you should be safe.
Related
I am using gorm to interact with a postgres database. I'm trying to ORDER BY a query that uses DISTINCT ON and this question documents how it's not that easy to do that. So I need to end up with a query in the form of
SELECT * FROM (<subquery>) ORDER BY column;
At first glance it looks like I need to use db.QueryExpr() to turn the query I have into an expression and build another query around it. However it doesn't seem gorm has an easy way to directly specify the FROM clause. I tried using db.Model(expr) or db.Table(fmt.Sprint(expr)) but Model seems to be completely ignored and fmt.Sprint(expr) doesn't return exactly what I thought. Expressions contain a few private variables. If I could turn the original query into a completely parsed string then I could use db.Table(query) but I'm not sure if I can generate the query as a string without running it.
If I have a fully built gorm query, how can I wrap it in another query to do the ORDER BY I'm trying to do?
If you want to write raw SQL (including one that has a SQL subquery) that will be executed and the results added to an object using gorm, you can use the .Raw() and .Scan() methods:
query := `
SELECT sub.*
FROM (<subquery>) sub
ORDER BY sub.column;`
db.Raw(query).Scan(&result)
You pass a pointer reference to an object to .Scan() that is structured like the resulting rows, very similarly to how you would use .First(). .Raw() can also have data added to the query using ? in the query and adding the values as comma separated inputs to the function:
query := `
SELECT sub.*
FROM (<subquery>) sub
WHERE
sub.column1 = ?
AND sub.column2 = ?
ORDER BY sub.column;`
db.Raw(query, val1, val2).Scan(&result)
For more information on how to use the SQL builder, .Raw(), and .Scan() take a look at the examples in the documentation: http://gorm.io/advanced.html#sql-builder
How do I escape the following query in Laravel, using Eloquent:
$someCollection->where(DB::raw("CONCAT(`field1`, ' ', `field2`)"), 'LIKE', "%".$user_input."%");
I'm wondering if Eloquent's where method is escaping the $user_input parameter, even when using DB::raw like this.
Any ideas?
The short answer is that yes, the 3rd parameter passed to where() called on a Model or an Eloquent Collection will be bound in the query, which will escape it to guard against injection attacks.
Under the hood, the Query Builder doesn't treat your 3rd parameter any differently depending on what you pass for your 1st parameter. So if you pass a raw Expression as the first query, or a column name, it's all good to Laravel, it will just use that value when constructing the WHERE clause. If you omit an operator as your second parameter, that's fine, too, as passing two parameters instead of 3 is like passing an = for your operator.
When Laravel submits your query to your database, it will actually look like this:
select * from `table_name` where CONCAT(`field1`, ' ', `field2`) LIKE ?
Laravel (technically PDO) then binds the value you submitted in place of the ? placeholder. As a result, any value you pass will be bound and escaped automatically for you.
Now, with escaping, no need to worry about the % operators, as PDO will leave them alone, and your LIKE clause would match any row where the concatenation of field1, a space, and field2, contains the string provided by the user anywhere in it.
You can test this out by passing just a " character as your input. If it wasn't escaped, the query would throw an error, but since it is escaped, the script runs fine - though it may return no results.
Hope that helps!
I am programming a Silverlight application in c#, which takes lists from a sharepoint.
I want the distinct elements from a specific column in the list.
After getting the query I can't handle with the var-datatype. The program exists everytime, when I want to make a datacast, for example in an ListItemCollection.
Here is the code:
ListItemCollection bla;
var result = bla.Select(m => m["Region"]).Distinct();
ListItemCollection a = (ListItemCollection)result; //Error happens here
LINQ deals with instances of IEnumerable<> or IQueryable<>. Distinct returns an IEnumerable<> or IQueryable<> depending on the type of the original collection. In your case, it returns an IQueryable
You are trying to cast that IQueryable to a ListItemCollection, which understandably results in an invalid cast exception.
You don't need to do something else to start working with the items. You can iterate over them with foreach, convert them to an array or list with ToArray() and ToList() etc
Linq provider for SharePoint does not support Distinct operator which is why this error occurs.
According to MSDN:
Some LINQ queries cannot be completely translated into CAML. However,
however such queries can, in principle, run correctly because they can
be executed in two stages. First, the LINQ to SharePoint provider
translates as much of the query into CAML as it can and executes that
query
Please refer Unsupported LINQ Queries and Two-stage Queries for a more details.
Two stage approach
To correct this error, you should cut your queries in two stages to force the first query execution before the second one. To do that, you should for example transform the first IEnumerable<T> in a list thanks to ToList() method.
The following example demonstrates how to return unique values from ListItemCollection object:
var result = items.ToList().Select(i => i["Region"].ToString()).Distinct(); //System.Linq.Enumerable.DistinctIterator<string> type
foreach (var item in result)
{
//...
}
I have the following query:
var query = db.Prog
.Where (a => a.Prog != "00000" && a.fn != "Koll")
.Select(a => new {a.Prog, a.MEfn})
.OrderByDescending(a => a.MEfn)
The query works fine but wondering if there are general rules on the order in which you write a Lambda linq query. Meaning, .Where comes before .Select, etc.
Can somebody enlighten me on the order in which LINQ needs to be written or best practices.
There isn't a best practice on the order in which you write a LINQ query, it will depend on if you want to do your filtering first, or your projection. For example in your case, you are projecting to an anonymous type which doesn't include the 'fn' property which your filter uses, so it wouldn't be available to use in a where clause if your select was first.
A better practice would be to give your properties less cryptic names. Also, 'fn' doesn't follow the PascalCase for property names, and if it's a field then it probably shouldn't be public.
Yours can be a good order.
Let's distinguish the case where db points to an SQL DB with a very good LINQ provider and the case db is an in-memory object. I guess it's the first.
In case you are using a LINQ to SQL provider, the statements are evaluated only when you materialize the query into an object, so the SQL optimizer (inside the DB) will take care of ordering of statements.
The vice versa occurs when your statements are run against in-memory collections or to materialized collections coming from LINQ to SQL. In that case they are executed sequentially, so you want to execute first those statements that reduce the number of results in the collection. Where is the best candidate!!!
The order that they should be in are completely dependent on the context of what you are doing. So if your OrderBy is simply formatting the data to be friendly to view, put it at the end after you have trimmed your collection, if your looking for the First value of a sorted collection then maybe you would need it before the collection is iterated to get the first.
I Just want to make sure I understand this correctly...
search is an object that contains a querystring.
Repo.Query returns an ObjectQuery<T>.
From my understanding the chained linq statements will filter the results after entity framework has returned all the rows satisfying the query. So really ALL the rows are being returned and THEN filtered in memory. So we are returning a bunch of data that we don't really want. There's about 10k rows being returned so this is kind of important. Just like to get my confusion cleared up.
var searchQuery = Repo.Query(search)
.Where(entity =>
entity.Prop1.ToUpper().Equals(prop1.ToUpper()) &&
entity.Prop2.ToUpper().Equals(prop2.ToUpper()))
.OrderBy(entity => Repo.SortExpression ?? entity.prop1);
Your Repo.Query(string query) function should return IQueryable<T>.
Then you can filter and order without getting all rows first.
IQueryable(Of T) Interface
hope this helps
If this is to SQL, this will most likely create a SQL query and filter on the server and not in memory.
As a matter of fact, the statement above wouldn't actually do anything.
It's only when you iterate over it that the query will be executed. This is why certain providers (like the EF to SQL one) can collapse expression trees into a SQL query.
Easiest way to check is to use LINQPAD or the SQL Profiler to see what query is actually is executed.