Kohana 3 cross-table update using Query builder - kohana

What is the proper way to construct a cross-table update in Kohana 3 using the DB query builder?
Currently I am just using a DB::expr but I know the query builder is smarter than that.
// update record
$rows_updated = DB::update(DB::expr('user_list_permissions INNER JOIN users ON user_list_permissions.user_id = users.id'))
->set($params)
->where('user_list_permissions.id', '=', $user_list_permission_id)
->where('users.account_id', '=', $this->account_id)
->execute();
And yes of course I tried using the "join" method like when building SELECT queries, but I receive an error:
ErrorException [ 1 ]: Call to undefined method Database_Query_Builder_Update::join()

So you are using the expression to do the join, it is possible to use the built in 'join' function on the 'on' function to achieve this behavior.
So in your example it would look something like:
$rows_updated = DB::update('user_list_permissions')
->join('users','INNER')
->on('user_list_permissions.user_id','=','users.id')
->set($params)
->where('user_list_permissions.id', '=', $user_list_permission_id)
->where('users.account_id', '=', $this->account_id)
->execute();
There isn't much on it but the docs do have a little bit at http://kohanaframework.org/3.2/guide/database/query/builder#joins

It's an old post but just to keep the record of my experiences in Kohana.
If you are using MySQL, it lets you to make the cross-table update avoiding the use of join as follow:
UPDATE table1, table2
SET table1.some_field = 'some_value'
WHERE table1.foreign_key = table2.primary_key AND table2.other_field = 'other_value'
Note that condition table1.foreign_key = table2.primary_key is the same you used in ON clause with JOIN. So you can write a cross-table update in Kohana follow that pattern avoiding the JOIN:
$rows_updated = DB::update(DB::expr('user_list_permissions, users'))
->set($params)
->where('user_list_permissions.user_id', '=', DB::expr('users.id'))
->where('user_list_permissions.id', '=', $user_list_permission_id)
->where('users.account_id', '=', $this->account_id)
->execute();

Related

How can I search on list of values using Lucene Query interface

Simplistic Problem description:
Lucene index has two fields per document: ID and NAME.
I want to make a query using the Lucene Query interface such that I can find all the documents where ID is 1 OR 2 OR 3 OR so on. The IDs to be searched will be in a list and can potentially have upto 30 elements.
If I was using the query parser I would have done something like
ID:(1 OR 2 OR 3)
But the application is already heavily committed to the Query interface and I want to follow the current pattern. Only way I can think of doing this with Query interface is create n term queries and group them using the Boolean query as below
BooleanQuery booleanQuery = new BooleanQuery();
(String searchId : lstIds)
{
booleanQuery.add(new TermQuery(new Term("ID", searchId)), BooleanClause.Occur.SHOULD);
}
But is there a better/more efficient way of doing this?
Combining queries togetheer with a BooleanQuery is the correct way to reproduce a query like ID:(1 OR 2 OR 3). The query parser will generate a BooleanQuery similar to what you provided for that syntax, so you are absolutely doing the right thing here.
You might be able to make use of PrefixQuery, NumericRangeQuery or TermRangeQuery to simplify matters, if they actually suit your needs in practice, but there is nothing wrong with what you are doing already.
BooleanQuery is the solution for handling OR operator as you have shown in the code but if you want simple alternative of the it you could also use simple Query and pass the IDs as "1 OR 2 OR 3".
Here is the code snippet lucene 7.
Query query = new QueryParser("ID", analyzer).parse("1 OR 2 OR 3");
TopDocs topDocs = searcher.search(query, 10);
OR if you have all the OR you could also use QueryParser default Operator.
Here is the code snippet for lucene 7.
QueryParser queryParser = new QueryParser("ID", analyzer);
queryParser.setDefaultOperator(QueryParser.Operator.OR);
Query query = queryParser.parse("1 2 3");
TopDocs topDocs = searcher.search(query, 10);
I hope that work for you.

How to query this with ORM?

I've using Kohana for a couple of weeks. One thing I noticed is that Kohana is missing eager loading (as far as I know). Let's say I have the following tables.
Subjects
id
name
Chapters
id
subject_id
name
Videos
id
chapter_id
name
When a user opens a subject page, I want to display all the chapters and videos. With ORM, I can do
$tutorials = ORM::factory('subject')->where('id','=', 1)->find();
foreach($tutorials as $tutorial)
{
$chapters = $tutorial->chapters->find_all();
foreach($chapters as $chapter)
{
$videos = $chapter->videos->find_all();
}
}
The above code is not efficient since it makes too many queries.
I thought about using join or database query builder, but both of them do not return a model object as their results. I also looked into with(), but it seems like it only works with one-to-one relationship.
using join on an ORM object returns an OPM object, but it doesn't return the data from the joining tables.
What would be my best option here? I would like to minimize # of queries and also want to get ORM objects a result. Whatever it would be, should return all the columns from tutorials, chapters, and videos.
First of all, your code is excess. ORM method find() returns 1 Model_Subject object. See
$chapters = ORM::factory('subject', 1)->chapters->find_all();
foreach($chapters as $chapter)
{
$videos = $chapter->videos->find_all();
}
With DB builder you can make just 2 requests. First get array of all chapters ids:
$chapters = DB::select('id')
->from('chapters')
->where('subject_id', '=', '1')
->execute()
->as_array(NULL, 'id');
Second - get all videos by ids as Model_Video object
$videos = DB::select('id')
->from('videos')
->where('chapter_id', 'IN', $chapters)
->as_object('Model_Video')
->execute()
->as_array();
So I guess you want something like this.
$videos = ORM::factory('Video')
->join(array('chapters', 'chapter'), 'LEFT')->on('video.chapter_id', '=', 'chapter.id')
->join(array('subjects', 'subject'), 'LEFT')->on('chapter.subject_id', '=', 'subject.id')
->where('subject.id', '=', $id)
->find_all();
Come to think of it, if the video belongs_to chapter belongs_to subject, try the following using with():
$videos = ORM::factory('Video')
->with('chapter:subject') // These are the names of the relationships. `:` is separator
// equals $video->chapter->subject;
->where('subject.id', '=', $id)
->find_all();
With things like this it often helps to think 'backwards'. You need the videos on that subject so start with the videos instead of the subject. :)
EDIT: The drawback of the second function is that it is going to preload all the data, it might be shorter to write but heavier on the server. I'd use the first one unless I need to know the subject and chapter anyway.

In a master detail relationship how to get a list of master entities without detail entities crm 2011?

I'm using CRM 2011 and I have a 1-n relationship between EntityA(master) and EntityB(detail).
I need to get the list of EntityA records that are not related to any EntityB records. How can I accomplish this inside a plugin using query expression?
I believe this should work (See the EDIT, it doesn't work):
var qe = new QueryExpression("entitya");
var entityBLink = qe.AddLink("entityb", "entityaid", "entityaid", JoinOperator.LeftOuter);
entityBLink.LinkCriteria.AddCondition("entitybid", ConditionOperator.Null);
It should create a SQL Statement that looks something like this:
SELECT
FROM entitya
LEFT OUTER JOIN entityb on entitya.entityaid = entityb.entityaid
AND ( entityb.entitybid IS NULL )
EDIT - Working version
var qe = new QueryExpression("entitya");
var entityBLink = qe.AddLink("entityb", "entityaid", "entityaid", JoinOperator.LeftOuter);
entityBLink.Columns.AddColumn("entitybid");
var entities = service.RetrieveMultiple(qe).Entities.
Where(e => !e.Attributes.Keys.Any(k => k.EndsWith(".entitybid"))).
Select(e => e.ToEntity<entitya>());
The SQL statement for the first query does get generated as is, but since the null check is on the join and it is a left join, all EnityA entities get returned.
The bad news is in CRM there is no way to perform a sub query, or specify in the where clause, a linked entity's properties. I really hope Microsoft spends some time with the next major release adding this type of functionality.
You can however perform the filter on the client side, which is what the C# code is doing above.

Kohana 3.2 ORM multiple records update

How can I update multiple records in Kohana 3.2's ORM?
For example this:
$menu = ORM::factory('menu');
$menu->where('active','=',1);
$menu->active=2;
$menu->save();
does not work, it inserts a new record.
Thanks
If you don't want to hardcode the table name maybe something like below
DB::update(ORM::factory('menu')->table_name())
->set(array('active' => '2'))
->where('active', '=', '1')
->execute();

How would I change this Query builder from Kohana 2.4 to Kohana 3?

I have had this website built for a few months and I am just getting on Kohana 3. I'd just like to convert this K2.4 query builder to K3 query builder.
return DB::select(array('posts.id', 'posts.created', 'posts.uri', 'posts.price', 'posts.description', 'posts.title',
'image_count' => db::expr('COUNT(images.id)')))
->from('posts')
->join('images')->on('images.post_id', '=', 'posts.id')
->group_by(array('posts.id'))
->order_by('posts.id', 'DESC')
->limit($limit)
->offset($offset)
->execute();
The only change you need to make, is drop the surrounding array from the DB::select(), and for the aliased field, use an array
The query builder in Kohana3 accepts any number of arguments, see http://kohanaframework.org/guide/database/query/builder
return DB::select('posts.id', 'posts.created', 'posts.uri',
'posts.price', 'posts.description', 'posts.title',
array('COUNT("images.id")', 'image_count'))
->from('posts')
->join('images')->on('images.post_id', '=', 'posts.id')
->group_by(array('posts.id'))
->order_by('posts.id', 'DESC')
->limit($limit)
->offset($offset)
->execute();

Resources