I am defining the many to many relationship between two objects (ModelA & ModelB for this example) through three tables/active record models in the following way:
ModelA --< ModelA_B >-- ModelB
Where ModelA_B contains a foreign key field to both ModelA and ModelB. So in the code for ModelA I have have added to the relations() function:
'modelbs' => array(self::MANY_MANY, 'ModelB', 'tbl_modelb(modela_id,modelb_id)'),
My question is do I still need the HAS_MANY relationship that was generated by Gii to represent the relation to the linking table ModelA_B or is this declared implicitly by the MANY_MANY above?
'modelabs' => array(self::HAS_MANY, 'ModelA_B', 'ModelA_Id'),
If you use a MANY_MANY relation, you don't need to define another HAS_MANY relation for the ModelA_B table.
But you could also use the through feature, which will replace the MANY_MANY relation at some point (probably in Yii 2.0 if i remember right). In this case you would define 2 relations:
'mobelabs' => array(self::HAS_MANY, 'ModelA_B', 'ModelA_Id'),
'modelbs' => array(self::HAS_MANY, 'Model_B', 'ModelB_Id', 'through'=>'modelabs'),
Now you have access to both related records: the ModelA_B via $modelA->modelabs and the ModelB via the $modelA->modelbs.
Related
I have a problem with HAS_ONE relation in Yii framework. The scenario is as follow:
We have a User class with relation to SubscriptionType:
'subscriptionType' => array(self::HAS_ONE, 'SubscriptionType', 'subscription_type_id')
And s SubscriptioType with relation to User:
'users' => array(self::HAS_MANY, 'User', 'subscription_type_id')
What is more, User has a Foreign Key to SubscriptionType defined in the database.
There are 3 subscription types predefined and all the registering users get one of them by default during the registration. They are saved in the DB, so in the registerAction I do:
//some assignments here
$subscription = SubscriptionType::model()->find('name=:name', array(':name'=>SubscriptionType::MONTHLY));
$newUser->subscriptionType = $subscription;
if($newUser->save()){
//redirect to some page
} else {
Yii::trace('User register failed', 'application.controllers.UserController');
}
The user don't get saved. I debuged it bit and I noticed, that subscriptionType is assigned but subscription_type_id is not, so the INSERT query is throwing the constraint violation.
Do I have to set the subscription_type_id explicitly? It doesnt make to much sense to me because it's against the idea of ORM, isnt' it?
I think you are defining the relations incorrectly. HAS_ONE is for the Parent side of a One-to-One relationship, and HAS_MANY is for the Parent side of a One-to-Many relationship. You need a BELONGS_TO on one of these which should be on the child side of the relationship. I am guessing that you user model should have the BELONGS_TO like this:
'subscriptionType' => array(self::BELONGS_TO, 'SubscriptionType', 'subscription_type_id')
The other issue you are having is that you are trying to assign a value to subscripionType when it is more like a read only attribute in that it is populated by the framework. In the case of a HAS_ONE, or a BELONGS_TO, this will be a CActiveRecord model. In the case of a HAS_MANY or MANY_TO_MANY, it will be an array of CActiveRecord models. These models are not saved when you save the parent model. However since they are indeed models, you can update and save these individual child models.
I Have three tables, contact, list and listmembers. Contacts from contact table are associated to lists from list table via listmembers table.
class Model_Contact extends ORM{
protected $_has_many = array(
'lists'=>array('model'=>'List', 'through'=>'listmembers', 'far_key'=>'dlid', 'foreign_key'=>'uid')
);
}
class Model_List extends ORM
{
protected $_has_many = array(
'contacts'=>array('model'=>'Contact', 'through'=>'listmembers', 'far_key'=>'uid', 'foreign_key'=>'dlid')
);
}
I have to update contact and list relationship in listmemebers table
- create new relationship between existing contact and existing list
- Remove relationship between contact and list
How can I achieve this in Kohana ORM? I can always create model for listmembers and directly add/delete on this model. But is there a way to handle via relationship without creating listmembers model?
I think the documentation explains it quite well: http://kohanaframework.org/3.2/guide/orm/relationships#hasmany-through
I have a View called View_CrossReference in Sybase. I want to create Model for this view.
This table has a column called Answer.
I have an another table and model called SurveyXref. In this table i have a column
called Answer_No.
I want to create a relationship between these models and get the data from Answer column from View_CrossReference and display into my grid in SurveyXref page.
IN view_crossreference model
has_one :survey_xrefs, :primary_key => :answer, :foreign_key =>
:answer_no
In survey_xrefs model
belongs_to :view_crossreference, :primary_key => :answer ,
:foreign_key => :answer_no
now simply in controller u can access
v.view_crossreference.answer
Without "Model", means you have created table via stand alone migration.
Could you please show me your code for better understanding?
I've just created two models and one "join table". Person, Adress (create_adresses_personss)
class Person < ActiveRecord::Base
has_and_belongs_to_many :streets
end
class Street < ActiveRecord::Base
has_and_belongs_to_many :persons
end
Now I want to add some data to these models in the db/seeds.rb file. The tutorial I follow just adds the objects:
person = Person.create :name => 'Dexter'
street.create[{:streetname => 'street1'},
{:streetname => 'street2'},
{:streetname => 'julianave'},
{:streetname => 'street3'}]
Question 1: Why is persons' data added differently than streets'? Is it just the tutorial that wants to show that there are many ways of adding data in the seeds.rb?
Question 2: The tutorial doesn't make the connections/joins in the seeds.rb. It does that in the rails console;
>>p1 = Person.find(1)
>>s1 = Street.find(1)
>>p1.streets << s1
Can't theese connections be made in the seeds.rb file?
Question 3: Would it be better to do this join with a "rich many_to_many-assocciation"?
Thanks for your time and patience with a beginner ;)
1) The first method is creating one object. The second method is creating multiple objects. However, for the second method you would need to do Street.create, not street.create.
2) Yes, you can do that in the seed file the same way.
3) The "Rich many-to-many" you're talking about is an association with a Join Model, I guess you're talking about. This is opposed to just a join table, which is what has_and_belongs_to_many does. To use a join model, you'll want to look up has_many :through. It's generally considered better to always use a proper join model, however I still use HABTM when I just need a quick, simple association. has_many :through allows for more options and more flexibility, but it is a little more complicated to setup (not that much, though). It's your decision.
One way that I like to create seed data for many-to-many associations is setting up one of the models, the adding a tap block that sets up the other models through the association.
Person.create!(:name => "Fubar").tap do |person|
3.times do |n|
person.streets.create!(:streetname => "street #{n}")
end
# OR
person.streets.create!([
{:streetname => "street 1"},
{:streetname => "street 2"},
... and so on
])
end
All tap is doing is executing the block with the object as it's only parameter. I find it convenient for seeds.
One other tip I would toss out there would be to have your model attribute names spaced on the words with underscores.
:street_name instead of :streetname
The difference is more profound when you start wanting to use some of the ActiveSupport helers that take model attributes and turn them into text strings for use in the UI.
e
:streetname.to_s.titleize # "Streetname"
:street_name.to_s.titleize # "Street Name"
And one last nitpick, you might want your join table to be addresses_people not addresses_persons since the rais inflector is going to pluralize person as people. The same would go for your controller on the Person model, PeopleController instead of PersonsController. Though maybe it will work with persons as well.
:person.to_s.pluralize # "people"
:people.to_s.singularize # "person"
:persons.to_s.singularize # "person"
I have first table called Cars that contains the informations about color of the car, weight, price etc.
Then I have the second table, for example Other_informations. This table contains another informations about that car from the first table.
In the first table (Cars) is the name of the car. If I need to create an associations between these two tables, I can use:
car.rb
has many :other_informations
otherinformation.rb
belongs_to :car
In this case I have to set the name of one column in the table Other_informations on car_id and the associations will be created.
To this point is everything ok.
But now - I need just one association to add (from the table Other_informations to the table Cars - the same type of associations as the first).
I tried to do something like this:
car.rb
has many :other_informations
otherinformation.rb
belongs_to :car
belongs_to :car2
And then in the view used:
data.car2.name_of_the_car_from_first_table**
But this unfortunately didn't work me... can anyone help me, please, if is something like this possible to do?
Thank you in advance
I am not sure if I understand your question - do you want to have OtherInformation to be shared among different Cars? Like OtherInformation can belong to many different Cars?
You need some kind of many-to-many relationship then. Have a read:
http://guides.rubyonrails.org/association_basics.html#choosing-between-has_many-through-and-has_and_belongs_to_many
EDIT (after reading your comments):
belongs_to car, :class_name => "Car", :foreign_key => "to_col1"
belongs_to another_car, :class_name => "Car", :foreign_key => "to_col2"
That assumes that your OtherInformation has two columns in the database table: to_col1 and to_col2 And here is how associations should work:
other_info = OtherInformation.first
first_car = other_info.car
second_car = other_info.another_car
second_car_name = other_info.another_car.name
#etc...