Tables not joining in Kohana 3.1 ORM - kohana-3

How do I get this to work?
$stuff = ORM::factory('mytable')
->with('user')
->with('other_stuff')
->find_all();
I've got all of my relationships set up and everything seems to be working when I do other queries. However, in the query above it is not joining table users to mytable. I think it may be because there can be many users for one mytable.
In the reference there is a method called join() which I think I might need to use here, but they don't give any information on it, and the stuff I've searched for on here does not work.
When I try to use join instead of with, it tries to join the table, but it doesn't include any "join on" information, just gives an empty ().
I know my ORM DB relationships are all set up correctly, so I'm a bit baffled.

Kohana has decent documentation, not looking in the right place is ... well, your problem.
ORM::with() is used for loading one-to-one (belongs to and has one) relations, though you have all the Database_Query_Builder methods to use with ORM on your disposal:
$stuff = ORM::factory('mytable')
->join('users','LEFT')
->on('users.mytable_id','=','mytables.id')
->find_all();

SELECT * from table1
LEFT JOIN table2
ON table1.id = table2.id
AND table2.flag = 'Y'
AND table2.siteid = '12'
WHERE table1.siteid = '12'
How the above query is written in ORM format of kohana? Is the below one is correct
$stuff = ORM::factory('table1')
->join('table2','LEFT')
->on('table1.id','=','table2.id')
->on('table2.flag','=','Y')
->on('table2.siteid', '=', '12')
->where('table1.id', '=', '12')
->find_all();

Related

Select one column from Type-ORM query - Node

I have a type ORM query that returns five columns. I just want the company column returned but I need to select all five columns to generate the correct response.
Is there a way to wrap my query in another select statement or transform the results to just get the company column I want?
See my code below:
This is what the query returns currently:
https://i.stack.imgur.com/MghEJ.png
I want it to return:
https://i.stack.imgur.com/qkXJK.png
const qb = createQueryBuilder(Entity, 'stats_table');
qb.select('stats_table.company', 'company');
qb.addSelect('stats_table.title', 'title');
qb.addSelect('city_code');
qb.addSelect('country_code');
qb.addSelect('SUM(count)', 'sum');
qb.where('city_code IS NOT NULL OR country_code IS NOT NULL');
qb.addGroupBy('company');
qb.addGroupBy('stats_table.title');
qb.addGroupBy('country_code');
qb.addGroupBy('city_code');
qb.addOrderBy('sum', 'DESC');
qb.addOrderBy('company');
qb.addOrderBy('title');
qb.limit(3);
qb.cache(true);
return qb.getRawMany();
};```
[1]: https://i.stack.imgur.com/MghEJ.png
[2]: https://i.stack.imgur.com/qkXJK.png
TypeORM didn't meet my criteria, so I'm not experienced with it, but as long as it doesn't cause problems with TypeORM, I see an easy SQL solution and an almost as easy TypeScript solution.
The SQL solution is to simply not select the undesired columns. SQL will allow you to use fields you did not select in WHERE, GROUP BY, and/or ORDER BY clauses, though obviously you'll need to use 'SUM(count)' instead of 'sum' for the order. I have encountered some ORMs that are not happy with this though.
The TS solution is to map the return from qb.getRawMany() so that you only have the field you're interested in. Assuming getRawMany() is returning an array of objects, that would look something like this:
getRawMany().map(companyRecord => {return {company: companyRecord.company}});
That may not be exactly correct, I've taken the day off precisely because I'm sick and my brain is fuzzy enough I was making too many stupid mistakes, but the concept should work even if the code itself doesn't.
EDIT: Also note that map returns a new array, it does not modify the existing array, so you would use this in place of the getRawMany() when assigning, not after the assignment.

Servicestack OrmLite "where exists" subquery

No matter how hard I tried I couldn't make it work and I'm not sure if it is possible.
I want to select all clients who have at least one order.
The first thing I tried was db.Exists as following:
SqlExpression<Client> exp = OrmLiteConfig.DialectProvider.SqlExpression<Client>();
exp.Where(x => Db.Exists<Order>(z => z.ClientId == x.Id));
but I get the following error
variable 'x' of type '[assembly].Client' referenced from scope '', but it is not defined`
Second try was using Join and SelectDistinct:
SqlExpression<Client> exp = OrmLiteConfig.DialectProvider.SqlExpression<Client>();
ev.Join<Client, Order>((b, a) => b.Id == a.ClientId)
.SelectDistinct(x => new { x.Id, x.ClientNumber, x.ClientNameName});
Although not optimal it worked, up to the moment when I needed paging for the result set through
ev.Limit(skip:((request.Page-1) * request.PageSize), rows:request.PageSize)
When using Limit the distinct logically get ignored in building the query, so I get now duplicate Clients.
Is there any other way, or in general is there away to handle subqueries in OrmLite?
Any help is appreciated.
ServiceStack OrmLite (currently at 4.0.x) does not have support for subqueries.
If you look at the 4.0.x docs , there is no discussion of subqueries. JOIN support has been added recently, but for advanced SQL, you need to write it yourself.
Honestly, at a certain point of complexity, SQL is more readable than advanced ORM/LINQ-style queries.

how SQL injection is done? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
XKCD SQL injection - please explain
What is the general concept behind sql injection ?
Being a rails developer
This is unsafe
Booking.find(:all, :conditions => [ 'bookings.user_id = #{params[user_id]]}'] )
and this is safe:--
Booking.find(:all, :conditions => [ 'bookings.user_id = ?', params[user_id]] )
am i right?
So my question is how the sql injection is done?
How those guys do some stuff like that. Any live example/ tutorial where somebody is showing this kind of stuff. Anything basic for knowing the logic.
SQL Injection happens when a programmer gets lazy. A vulnerable query would look like this:
DECLARE #cmd varchar(256)
SET cmd='SELECT #col FROM Table'
EXEC #cmd
With #col being a variable passed into a stored procedure.
Usually, the user would enter a column in that already exists for that variable. But a more devious user could enter something like this:
* FROM Table; DROP DATABASE data;--
The * FROM Table; finishes off the previous statement. Then, DROP DATABASE data; is the payload that does bad things, in this case, dropping the database. Finally, the -- comments out the rest of the query so it doesn't get any errors from the injection.
So, instead of executing this:
SELECT column
FROM Table
You get this:
SELECT *
FROM Table;
DROP DATABASE data;
--
Which is not good.
And this:
All the user has to do is enter:
1234; DROP TABLE BOOKINGS
...
I don't know about rails, but by doing this Booking.find(:all, :conditions => [ 'bookings.user_id = #{params[user_id]]}'] ), you risk that the user give to user_id the value 1 OR 1=1 and as you can see, it will modify your request.
With more injection you could do something like 1; DROP TABLE BOOKINGS etc.
Basically injection is just "hijacking" a basic request to add yours.
Bobby tables
If you have a simple query like
SELECT * FROM bookings WHERE user_id = ORDER BY user_id ASC;
if you don't check user id, it can close your query, then start a new (harmful one) and discard the rest. To achieve this, generally, you would enter something like
1; DELETE FROM bookings; --
initial ; closes the good query, the bad query comes next, then it is closed with ; and -- makes sure that anything that would come next in the good query is commented out. You then end up with
SELECT * FROM bookings WHERE user_id = 1; DELETE FROM bookings; -- ORDER BY user_id ASC;
If your data in properly cleaned and sanatized, a user can try to get their own SQL code to run on the server. for example, let's say you have a query like this:
"SELECT * FROM products WHERE product_type = $type"
where type is unchanged user input from a text field. now, if I were to search for this type:
(DELETE FROM products)
You are gonna be in a world of hurt. This is why it's important to make sure all user input in sanatized before running it in the DB.
Plenty of excellent papers on the theory of SQL injection here:
sql injection filetype:pdf
Should be easy enough to hunt one down that is specific to your language/DB combination.

subsonic query problem

I'm using subsonic 2.2 in an app. I'm running a little complicated query in I have used both "And" and "Or" for a field, I'm little confused about how it is going to be translated into sql statement
MytableCollection col = DB.Select().From("mytable").Where("prop1").IsEqualTo(obj.prop1)
.And("prop2").IsEqualTo(obj.prop2)
.And("prop3").IsEqualTo(obj.prop3)
.Or("prop1").IsEqualTo(1)
.ExecuteAsCollection<MytableCollection>();
I want to perform query like this.
select * from mytable where (prop1=obj.prop1 or prop1=1) and prop2=obj.prop2 and prop23=obj.prop3
As Andra says you can use AndExpression. This should do what you want:
MytableCollection col = DB.Select().From(Mytable.Schema)
.Where(Mytable.Columns.Prop2).IsEqualTo(obj.prop2)
.And(Mytable.Columns.Prop3).IsEqualTo(obj.prop3)
.AndExpression(Mytable.Columns.Prop1).IsEqualTo(obj.prop1)
.Or(Mytable.Columns.Prop1).IsEqualTo(1)
.ExecuteAsCollection<MytableCollection>();
N.B. using MyTable.Schema and MyTable.Columns will catch a lot of issues at compile time if you rename tablees and will save errors caused by mistyping
Something that is REALLY useful to know about is also the following two methods to call in your query building:
.OpenExpression()
and
.CloseExpression()
Mix those bad buoys and you have a lot better control over knowing where things start and finish
you can use expression in subsonic 2.2.
MytableCollection col = new Select(Mytable.Schema)
.WhereExpression("prop1").IsEqualTo(obj.prop1).Or("prop1").IsEqualTo(1)
.AndExpression("prop2").IsEqualTo(obj.prop2)
.AndExpression("prop3").IsEqualTo(obj.prop3)
.ExecuteAsCollection<MytableCollection>();

Subsonic : Same column name different tables

I have a query where I need to do a "Where" clause for two different columns in two different tables but subsonic creates the same parametrized parameter name for both which is causing an issue. How can I fix this?
string _RawSql = new Select()
.From(Tables.Table1)
.InnerJoin(Tables.Table2)
.InnerJoin(Table3.SidColumn, Table2.Table3SidColumn)
.Where(Table1.SidColumn).IsEqualTo(2)
.And(Table3.SidColumn).IsEqualTo(1)
.BuildSqlStatement();
The query this is creating is
SELECT ....
FROM [dbo].[Table1]
INNER JOIN [dbo].[Table2] ON [dbo].[Table1].[Table2Sid] = [dbo].[Table2].[Sid]
INNER JOIN [dbo].[Table3] ON [dbo].[Table2].[Table3Sid] = [dbo].[Table3].[Sid]
WHERE [dbo].[Table1].[Sid] = #Sid
AND [dbo].[Table3].[Sid] = #Sid
Note that in the last two lines its using #Sid for both Table1 and Table3. How go I do it so it uses #Sid0 and #Sid1?
Any help would be appreciated. Thanks
Thanks for the response, I really appreciate it. I am using 2.1
I am already using TableColumn. Below is the c# subsonic code...
.Where(Table1.SidColumn).IsEqualTo(2)
.And(Table3.SidColumn).IsEqualTo(1)
which creates the following sql when viewed in sql profiler
WHERE [dbo].[Table1].[Sid] = #Sid
AND [dbo].[Table3].[Sid] = #Sid
Could you please show me how can I replace these lines with the way you are suggesting? I would really rather not use literal "Table2.Sid = 2"
ranmore, the issue is same with variables or with constants.
I have even tried
.Where("Table1.Sid").IsEqualTo(2)
.And("Table3.Sid").IsEqualTo(1)
This creates the query as
WHERE Table1.Sid = #Table1.Sid0
AND Table3.Sid = #Table3.Sid1
I finally get different parametrized vars in this case but now SQL Server complains because it does not like . in the parametrized var names.
I have no clue how to perform a join with 2 where clauses for 2 different tables!
What version are you using? In 2.2 You can use the TableColumn object to get around this (it may be the same for 2.1 as well. So instead of using the struct, as you're doing, you can use the object (Table2.SidColumn).
If push comes to shove - you can override everything with a string - so in your case you could use "Table1.Sid" and "Table2.Sid" right in the Where() method.
I haven't been able to confirm this, but perhaps the problem only happens with literals? (not sure if your sample code is like that for brevity's sake)
int table1SidColumnValue = 2;
int table3SidColumnValue = 1;
.Where(Table1.SidColumn).IsEqualTo(table1SidColumnValue)
.And(Table3.SidColumn).IsEqualTo(table2SidColumnValue)
I remember seeing a problem with this when using multiple .In() clauses with literal values, not sure if that applies to your problem though.
I'm not sure what version of the code I have but your query produces numbered parameters for me.
If you look at Line 255 of ANSISqlGenerator.cs
https://github.com/subsonic/SubSonic-2.0/blob/master/SubSonic/SqlQuery/SqlGenerators/ANSISqlGenerator.cs
c.ParameterName = String.Concat(col.ParameterName, query.Constraints.IndexOf(c));
The where parameters really should have numbers appended to them... maybe pull the latest version?

Resources