I have a many-to-many structure mapped to entity framework. This is a sample of what it looks like:
User UserTag Tag
------- -------- -------
IdUser(PK) IdUserTag(PK) IdTag(PK)
Name IdUser(FK) TagName
Desc IdTag(FK) Active
Now, I needed to exclude from any request of any method the viewing of Tags that were Active=false.
First, I tried doing it manually in every method, like:
public User GetById(int id)
{
var item = UserRepository.GetById(id); //This is just a repository that calls the EF context
//EF automatically maps it to the *UserTags* property
foreach(var tag in item.UserTags)
{
if(tag.Tag.Active == false)
item.UserTags.Remove(tag);
}
}
But it throws the following exception:
The relationship could not be changed because one or more of the foreign-key properties is non-nullable
So, I wanted to know if there's a way to conditionaly filter every request made to a specific table, whether it is select or a join request.
Try this in your GetById method:
var user.UserTags = dbContext.Entry(user)
.Collection(u => u.UserTags)
.Query()
.Where(ut => ut.Active == true)
.ToList();
The supplied code fails because it is attempting to remove items from the data entities not the list. If you want to pass the data entity around instead of the data model, you need to not use Remove. Something like the below (untested should work).
tags = item.UserTags.Where((ut) => ut.Active).ToList();
This line will get you a list of data entities that are active. However, you should really map all of this into a data model (see AutoMapper) and then you would not be removing items from the database.
I have a problem with certain generated query, the query does an inner join with a table that has some same field.
How can I have the query with the table name in each field, basically what i want is that:
Convert this:
select "list_id", "date_time","plate"...
TO:
select register."list_id", register."date_time",register."plate"...
I think with alias to the field name also could be accomplished but i dont know how to add the alias in atk4
If someone wants to see the full query and atk error:
Application Error: Database Query Failed
Exception_DB, code: 0
Additional information:
pdo_error: SQLSTATE[42702]: Ambiguous column: 7 ERROR: column reference "date_time" is ambiguous LINE 1: select "date_time","plate",(select "name" from "lane" whe... ^
mode: select
params:
query: select "date_time","plate",(select "name" from "lane" where "register"."lane_id" = "lane"."id" ) "lane",(select "name" from "camera" where "register"."camera_id" = "camera"."id" ) "camera",(select "detail"."id" from "detail" where "register"."detail_id" = "detail"."id" ) "detail","id","lane_id","camera_id","detail_id" from "register" inner join "detail" on "detail"."id" = "register"."detail_id" order by (select "detail"."id" from "detail" where "register"."detail_id" = "detail"."id" )
This is how im making the model. This model has 3 related fields in other tables, with those, all is OK. But i want to have one more field (field name from table List), and List is not directly related to Register, is only related throught Detail. So i have to get it throught Register->Detail->List..
table Register(id, plate, detail_id,..)---->hasOne(detail_id)-->table Detail(id, list_id, date..)---->hasOne(list_id)---->table List(id,name,..)
model class:
class Model_Register extends Model_Table {
public $table='register';
function init(){
parent::init();
$this->addField('date_time')->sortable(true)->defaultValue(date('Y-m-d H:m:i'))->type('date')->mandatory(true);
$this->addField('plate')->sortable(true)->mandatory(true);
$this->hasOne('Lane', 'lane_id')->sortable(true)->system(true);
$this->hasOne('Camera', 'camera_id')->sortable(true);
$this->hasOne('Detail', 'detail_id')->sortable(true);
}
}
And after in the page class i do the join, yes I know is detail at this moment is redudant im only trying...
$register = $crud->setModel('Register');
$q = $register->_dsql();
$q->join('detail', 'detail_id', 'inner');
$q->join('list', 'list_id', 'inner');
How can I have this field from the List field?? Any solution will be welcomed..
Thanks in advice!! Im breaking my head with this! ;)
Thanks for your time guys, finally I found the solution with the called: Chained joins
Example from documentation:
$perm = $this->join('permission');
$res = $perm->join('resource');
Belive or not that was my real problem! Thanks all anyway
try to add 'table_alias' property for your Models
class Model_Yours extends Model_Table {
public $table_alias = '_alias';
}
Default value for this property is null - link
So if you add any value it can be used here
Not sure if this will help :(
$t1 = $this->add('Main_Table');
$t2 = $t1->leftJoin('joined_table_name');
$t2->addField('joined_table_field_ALIAS','joined_table_field_REALNAME');
check SQL_Model::addField() method here
I am new to backbone.
After much confusion about not being able to add some of my models to a collection and sometimes getting the wrong model using collection.get(id) I found out that my model ids are colliding with backbones cids.
My model ids are something like "c7" or "c5e6". While the later is no problem "c7" is backbones own cid for the seventh element of the collection.
So if I ask for collection.get('c7') and expect null I instead get the element that was given the cid "c7" by backbone. And if I add an element with id "c7" I will never get it back with get("c7").
I wonder if I am the first one with this problem, I did not find anything about a syntax restriction of backbone ids, is there a way to solve this? As a workaround I will save my own ids in a custom attribute, and have to use collection.where instead of collection.get.
Any better ideas?
If you look at Backbone source code, you will see that the cid in a model is determined in the constructor by
this.cid = _.uniqueId('c');
c is an arbitrary prefix which means you could disambiguate your ids by overriding _.uniqueId, something like
_._uniqueId = _.uniqueId;
_.uniqueId = function(prefix) {
if (prefix === 'c') {
prefix = 'cc';
}
return _._uniqueId(prefix);
};
Without the override : http://jsfiddle.net/nikoshr/KmNSr/ and with it : http://jsfiddle.net/nikoshr/KmNSr/1/
Unfortunately, this does look like an edge case problem with no real solution. Looking at the Backbone source, we can see in the Backbone.Collection.set method that Backbone mixes both your IDs and their internal CIDs in the same object:
set: function(models, options) {
// ...
this._byId[model.cid] = model;
if (model.id != null) this._byId[model.id] = model;
// ...
return this;
},
The _byId object holds all IDs which causes your issue. Here is the Backbone.Collection.get method:
get: function(obj) {
if (obj == null) return void 0;
return this._byId[obj.id != null ? obj.id : obj.cid || obj];
},
When you call it using a non-existent ID (of your own) like "c7", the return ... line becomes return this._byId["c7"];. Since _byId has references to yours and Backbone's IDs, you're getting their entry returned when you expected null.
nikoshr has a great solution in the answer below.
My multi-level MVCGrid/MVCForm/MVCGrid saga continues....
I am using nested MVCGrids with expander buttons that invoke MVCForms to perform different data operations. ALL mySQL tables in this process have an "id" data element and that is the primary key for each table. Each mySQL table also has a point to its parent when necessary using _id naming convention. All of the foreign-keys have been setup in mySQL to work this way as well.
The model for the parent is like this:
class Model_uidcontrol extends Model_Table {
public $entity_code='uidcontrol';
public $table_alias='uc';
function init(){
parent::init();
The model for the child is like this:
class Model_uiddetails extends Model_Table {
public $entity_code='uiddetails';
public $table_alias='ud';
function init(){
parent::init();
Each model has its own "id" and a pointer to its parent.
The expander column in the MVCGrid (parent) invokes this child function:
$um=$this->add('MVCForm');
$um->setModel('uiddetails')
->loadData(($_GET['uidcontrol_id']));
I have tried this in the child model:
$this->addRelatedEntity('uc','uidcontrol','uidcontrol_ID');
and this as well:
$this->addField('uidcontrol_id')
->refModel('Model_uidcontrol')
->caption('System Info')
->visible(true);
I've tried each technique separately and together to get child records to be coordinated with the proper parent.
debug() shows this
where
ud.id = '121'
ud.uidcontrol_id = '121'
OK, I understand the $GET and how it works and how that relates to dsql - at least I think I do.
What I can't figure out is how to tell MVCForm to use "ud.uidcontrol_id = '121 " that come
via the $GET when building the dsql for data loading and not use 'ud.id'
In the above example, there is a parent record "uidcontrol" with that id. I forced the 'id' of the child record to be 121 to see if it would pull data and display it in the form. OK, data displays as it should.
When I try this parent whose 'id' = 10, debug() produces this
ud.id = '10'
ud.uidcontrol_id = '10'
and no data is returned. There is a uidcontrol record with id = 10 but the dsql is trying to match to ud.id = 10 as well.
I can post more of what I am working to clarify what I am trying to do if that helps.
Ideally, I would like to tell MVCForm "Hey! Don't use the 'id' data element when building the dsql, use the one I am supplying instead. Problem is, I can't figure out how to do that... but I've learned a bunch along the way. Me thinks that I am probably "over thinking" something here.
Thanks for any suggestions!
Monday Feb 6th Notes:
var_dump($_GET); says:
'id' => string '10' (length=2) <=== uidcontrol.id
'uidcontrol_id' => string '10' (length=2) <=== uidcontrol.id
I write this:
$um->setModel('uiddetails')
->addCondition('uidcontrol_id',($_GET['id']))
->loadData(($_GET['id']));
And the SQL debug shows this being built:
where
ud.id = '10'
ud.uidcontrol_id = '10'
The issue is that I want ONLY " ud.uidcontrol_id = '10' ". Table uiddetails has its own id of 125 and a uidcontrol_id value of 10. As a result of that, the query doesn't return a record.
The loadData method only loads records by their id. To link the "child" model through his referenced record you must use setMasterField or addCondition to instruct the model to filter on the relationship.
If I do getLastInsertId() immediately after a save(), it works, but otherwise it does not. This is demonstrated in my controller:
function designpage() {
//to create a form Untitled
$this->Form->saveField('name','Untitled Form');
echo $this->Form->getLastInsertId(); //here it works
}
function insertformname() {
echo $this->Form->getLastInsertId(); //this doesnt echo at all
}
Please suggest a way to get the functionality I want.
CakePHP has two methods for getting the last inserted id: Model::getLastInsertID() and Model::getInsertID().
Actually these methods are identical so it really doesn't matter which method you use.
echo $this->ModelName->getInsertID();
echo $this->ModelName->getLastInsertID();
This methods can be found in cake/libs/model/model.php on line 2768
Just use:
$this->Model->id;
In Cake, the last insert id is automatically saved in the id property of the model. So if you just inserted a user via the User model, the last insert id could be accessed via $User->id
id - Value of the primary key ID of
the record that this model is
currently pointing to. Automatically
set after database insertions.
Read more about model properties in the CakePHP API Docs: http://api.cakephp.org/2.5/class-AppModel.html
Edit: I just realized that Model::getLastInsertID() is essentially the same thing as Model->id
After looking at your code more closely, it's hard to tell exactly what you're doing with the different functions and where they exist in the grand scheme of things. This may actually be more of a scope issue. Are you trying to access the last insert id in two different requests?
Can you explain the flow of your application and how it relates to your problem?
You'll need to do an insert (or update, I believe) in order for getLastInsertId() to return a value. Could you paste more code?
If you're calling that function from another controller function, you might also be able to use $this->Form->id to get the value that you want.
Try using this code in your model class (perhaps in AppModel):
function get_sql_insert_id() {
$db =& ConnectionManager::getDataSource($this->useDbConfig);
return $db->lastInsertId();
}
Caveat emptor: MySql's LAST_INSERT_ID() function only works on tables with an AUTO_INCREMENT field (otherwise it only returns 0). If your primary key does not have the AUTO_INCREMENT attribute, that might be the cause of your problems.
this is best way to find out last inserted id.
$this->ModelName->getInsertID();
other way is using
$this->ModelName->find('first',array('order'=>'id DESC'))
There are several methods to get last inserted primary key id while using save method
$this->loadModel('Model');
$this->Model->save($this->data);
This will return last inserted id of the model current model
$this->Model->getLastInsertId();
$this->Model-> getInsertID();
This will return last inserted id of model with given model name
$this->Model->id;
This will return last inserted id of last loaded model
$this->id;
Try to use this code. try to set it to a variable so you can use it in other functions. :)
$variable = $this->ModelName->getLastInsertId();
in PHP native, try this.
$variable = mysqli_insert_id();
This will return last inserted id of last loaded model
$this->id;
This will return last inserted id of model with given model name
$this->Model->id;
This will return last inserted id of the model current model
CakePHP has two methods for getting the last inserted id:
Model::getLastInsertID() and Model::getInsertID().
echo $this->ModelName->getInsertID();
echo $this->ModelName->getLastInsertID();
Below are the options:
echo $this->Registration->id;
echo $this->Registration->getInsertID();
echo $this->Registration->getLastInsertId();
Here, you can replace Registration with your model name.
Thanks
Use this one
function designpage() {
//to create a form Untitled
$this->Form->saveField('name','Untitled Form');
echo $this->Form->id; //here it works
}
You can get last inseted id with many ways.Like Model name is User so best way to fetch the last inserted id is
$this->User->id; // For User Model
You can also use Model function but below code will return last inserted id of model with given model name for this example it will return User model data
$this->User->getLastInsertId();
$this->User->getInsertID();
When you use save(), the last insert ID is set to the model’s $id property. So:
if ($this->Model->save()) {
printf('Last insert ID was %s', $this->Model->id);
}
Each time a save method is called on a model, cake internally calls Model::getLastInsertId() and stores the result into model class attribute id, so after calling save() it is not necessary to call Model::getLastInsertId() or inserId(), as tha value can be directly accessed like this
$id = $this->id;// within a model
$id = $this->{$this->modelName}->id;// in a controller
After insertion of data, we can use following code to get recently added record's id:
$last_insert_id=$this->Model->id;
each time you perform an insert operation on any model, cake internally fetchesthe last insert Id and Sets to Model->id attribute.
so one can access it directly by $Model->id;,
no need to query again for lastInsertId.
I think it works with getLastInsertId() if you use InnoDB Tables in your MySQL Database. You also can use $this->Model->id
$Machinedispatch =
$this->Machinedispatch->find('first',array('order'=>array('Machinedispatch.id DESC')));
Simplest way of finding last inserted row. For me getLastInsertId() this not works.
Actually you are using the getLastInsertId or getInsertId in a wrong manner.
getLastInsertId() is meant to work only after save() method.
It will even not work after a manual insert, as cake engine is storing the mysql_insert_id under $this->_insertID inside the save method which can be retrieved via the getLastInsertId or getInsertId.
Now in your case
$this->Model->id
OR
$this->Model->find('first',array('order'=>'id DESC'))
Will do.
This is interesting, I also stumbled upon this issue. What you asked perhaps how to get the last ID of a certain model regardless of it's state, whether it's just been inserted or not. To further understand what getInsertID does, we need to take a look at the source:
Link 1: http://api20.cakephp.org/view_source/model#line-3375
public function getInsertID() {
return $this->_insertID
}
Yup, that's the only piece of code inside that function. It means that cakephp caches any last inserted ID, instead of retrieve it from the database. That's why you get nothing if you use that function when you haven't done any record creation on the model.
I made a small function to get the last ID of a certain table, but please note that this should not be used as a replacement of getLastID() or getLastInsertID(), since it has an entirely different purpose.
Add the function lastID() to the AppModel as shown below so that it can be used system wide. It has it's limit, which can't be used on model with composite primary key.
class AppModel extends Model {
public function lastID() {
$data = $this->find('first',
array(
'order' => array($this->primaryKey . ' DESC'),
'fields' => array($this->primaryKey)
)
);
return $data[$this->name][$this->primaryKey];
}
}
Original Source : Class Model
In CakePHP you can get it by:
Model::getInsertID() //Returns the ID of the last record this model inserted.
Model::getLastInsertID() //Alias to getInsertID().
$this->Model->field('id', null, 'id DESC')