I'm having trouble on inserting a new record having a parent .
<?php
/**
* This is the model class for table "tbl_a".
* #property integer $id
....
*/
class A extends CACtiveRecord{
}
?>
<?php
/**
* This is the model class for table "tbl_b".
* #property integer $id
....
* The followings are the available model relations:
* #property A $a
*/
class B extends CACtiveRecord{
//codes...
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'a' => array(self::BELONGS_TO , 'A', 'id'),
);
}
}
?>
This is the structure of my model classes.
here the 'id' of tbl_b is set as the primary key and also is the foreign key referencing tbl_a. 'id' of tbl_a is its primary key.
My issue here is, when i tried to save model object of B ($b->save()), after setting all the attributes excluding 'id' (But the property 'a' of the object[$b] is set with an active record of model 'A' say having primary key 10), an exception is thrown on inserting the record because of no 'id' is set to it. But when I tried the same after setting the 'id' of the model object, it inserted correctly.
Why we need to set the foreign key attribute of the child model even the related property is set?
Is there any solution for this. So that the foreign key reference id is taken automaticaly from the related model obj?
Thanks in advance.
Is will be automatically generated only if your database support it. Yii will not create id by himself. If you are using MySQL as your RDMS, primary key should be marked as auto_increment. But in your situation, you are using foreign key as your primary key. So the most preferable way for you is to overload beforeSave method of B model and fetch a::id as b::id:
public function beforeSave()
{
if (parent::beforeSave())
{
$this->id = $this->a->id;
return true;
}
return false;
}
Related
I have a chat table that both a user and admin can chat the table is defined as follow:
id, from_id, to_id, message, is_from_admin.
what I want is, if the is_from_admin is true laravel should use the admin table at sql level for the from. otherwise it should use the user table for from and same applies to the to field. Thanks
If you have the chance, I'd rework the table a bit and name it like so:
id, from_user_type, from_user_id, to_user_id, message
The pair from_user_type and from_user_id can be used to creat a custom polymorphic relation ("type" refers to the model/table name, and "id" refers to the id of a row in this table) as seen here: https://laravel.com/docs/9.x/eloquent-relationships#one-to-many-polymorphic-relations .
If you also want to send admin-to-admin, you should also add to_user_type, to_user_id so you can create a polymorphic relationship on the receiving side as well.
The polymorphic relation will look something like this:
class ChatMessage
{
public function fromUser()
{
// This function should automatically infer `from_user_type` and `from_user_id`
// from this function name.
return $this->morphTo();
}
}
class AdminUser
{
public function chatMessages()
{
return $this->morphMany(ChatMessage::class, 'fromUser');
}
}
Laravel can not solve what you are doing, which is a polymorphic relationship, based on a boolean. Theoretically you could bind the polymorphic class definition to 0 or 1, but this is a hack at best. Alternatively you could rewrite your table structure to support polymorphic relations.
Instead i would say you achieve something that is working, with what you have. Create two relationships combined with some logic in an accessor. Create a relationship for the admin and for the user.
Chat extends Model
{
public function fromAdmin()
{
return $this->belongsTo(Admin::class, 'from_id')->where('is_from_admin', true);
}
public function fromUser()
{
return $this->belongsTo(User::class, 'from_id')->where('is_from_admin', false);
}
}
Now create the accessor on the Chat model, using your new relationships.
public function getFromAttribute()
{
return $this->fromAdmin ?? $this->fromUser;
}
With this approach, you should be able to access the attribute like this.
Chat::find(1)->from; // either a user or admin based on the data.
I just want to update a column table based on a condition. Here my code :
this.session.Query<EventEntity>()
.Where(e => [...])
.Update(c => new { Enabled = true });
This call generates the following SQL :
insert into HT_event SELECT evententit0_.Id as Id FROM event evententit0_ WHERE [...]
UPDATE event SET Enabled=? WHERE (Id) IN (select Id from HT_event)
Why NHibernate creates a temp table to store ids instead of directly generates a correct IN clause ? How can I disable this behavior ?
To give more information, I use a table per class hierarchy inheritance mapping with mapping by code. My EventEntity is an abstract class :
public abstract class EventEntity { ... }
public class EventMap : ClassMapping<EventEntity> { ... }
I have a few others entities that inherit from EventEntity
public abstract class MatchEntity { ... }
public class MatchMap : JoinedSubclassMapping<MatchEntity> { ... }
Thx for your help !
Hibernate propose a way to customize the bulk id strategy, but it's not available for NHibernate at this moment : https://github.com/nhibernate/nhibernate-core/issues/2004.
If you have a data model in which one table is a guid table with just a guid column, and many tables have a primary key referencing that guid, how would you recommend incorporating this type of logic into Yii? To create a new model of any guidable thing, you have to create a guid first. Where is the right place to put this sort of logic?
Edit: To be more specific, here is the issue I am facing:
I have a table of guids, tbl_guid, with one column guid that is a MySQL BIGINT
Some tables, like tbl_foo, have a PK guid referencing guid in tbl_guid
The Foo model has the relation self::BELONGS_TO, 'Guid', 'guid'
I do not want to create a new guid until I am definitely ready to create Foo
I'd like to somehow delay the saving of my guid until I'm actually saving (and have otherwise validated) Foo
However, Foo never validates, because it doesn't have a guid.
Edit 2: I've posted my own answer, but I am hoping somebody has a better answer/improvement to suggest. Here are the issues with my answer:
How can we force the owner to comply with some interface, so we don't have to throw in a bunch of conditionals to check for whether or not the owner has an attribute or method, etc
Even though the database will not accept null for guid, it still seems wrong to remove guid from the list of required attributes.
This is the best I've been able to come up with:
Create a new CActiveRecordBehavior for guidable models:
public function beforeSave() {
if (!$this->owner->guid) {
$guid = new Guid;
$guid->save();
$this->owner->guid = $guid->guid;
}
}
Attach the behavior on the model, or define it in the model's behaviors array.
public function init() {
$behavior = new GuidBehavior;
$this->attachBehavior('GuidBehavior', $behavior);
}
Remove the required-ness of guid so validation doesn't fail:
array('name', 'required'), //guid isn't here
Test
$brand->save();
Inheritance. If you implemented my BaseModel code a while ago, you can override the __construct() method in the BaseModel to create an instance of the GUID class.
BaseModel:
public function __construct()
{
parent::__construct();
$newGuid = new GUID();
return $this;
}
See http://www.yiiframework.com/doc/api/1.1/CActiveRecord
We have the following Domain objects :-
public class UserDevice : BaseObject
{
// different properties to hold data
}
public class DeviceRecipient:BaseObject
{
public virtual UserDevice LastAttemptedDevice{get;set;}
}
Hence the sql schema created based on this using fluent nhibernate automapper is like
DeviceRecipient's table is having primary key of UserDevice as a foreign key i.e UserDevice_Id.
Now, When we try to delete UserDevice object it gives a sql exception for foreign key constraint. What we want to do is :-
Delete the UserDevice object , hence the UserDevice row without deleting the DeviceRecipient as it will be used somewhere else in domain model. We just want to set null to UserDevice_Id column of DeviceRecipient when we delete UserDevice.
We want to do it using fluent nhibernate conventions as we use Automapping.
Any help will be appreciable.. Thanks in advance.!
As I can see you have uni-direction many-to-one relation. So firstly you have to write following override:
public class DeviceRecipientOverride : IAutoMappingOverride<DeviceRecipient>
{
public void Override(AutoMapping<DeviceRecipient> mapping)
{
mapping.References(x => x.LastAttemptedDevice)
.NotFound.Ignore(); // this doing what you want.
}
}
Secondly you could convert it to automapping convention, if you have more places with this behavior.
public class ManyToOneNullableConvention : IReferenceConvention
{
public void Apply(IManyToOneInstance instance)
{
var inspector = (IManyToOneInspector) instance;
// also there you could check the name of the reference like following:
// inspector.Name == LastAttemptedDevice
if (inspector.Nullable)
{
instance.NotFound.Ignore();
}
}
}
EDIT:
From the NHibernate reference
not-found (optional - defaults to exception): Specifies how foreign
keys that reference missing rows will be handled: ignore will treat a
missing row as a null association.
So when you set not-found="ignore" SchemaExport/SchemaUpdate will just not create the FK for you. So if you have the FK then you need to delete it or set OnDelete behavior of the FK to Set Null. Assuming that you are using Microsoft Sql Server:
ALTER TABLE [DeviceRecipient]
ADD CONSTRAINT [FK_DeviceRecipient_LastAttemptedDevice]
FOREIGN KEY ([LastAttemptedDevice_ID])
REFERENCES [UserDevice]
ON DELETE SET NULL
I need to assing a value (a previously created entites Id)to reference column in a doctrine 2 model, For example
/**
* #Entity #Table(name="products")
*/
class product {
/**
*
* #ManyToOne(targetEntity="category")
*/
protected $category;
public function assignCategoryId($id) {
$this->category_id=$id;
}
}
I assume that category_id is created by doctrine 2 as referance column name,
Don't ask why I want to assign the id not the object itself, because it has to be this way. Is there a way to do this ? Any idea ?
While #Orbling's answer is correct you don't actually have to load the entity from the database. Instead you can use a reference:
// method on Product entity
public function setCategory(Category $category)
{
$this->category = $category;
}
// then set the category on the product
$product->setCategory($entityManager->getReference('category', $categoryId));
You can find the documentation here.
In order to do that, you would create a category entity and assign it to the relationship property.
$category = $entityManager->find('category', $categoryID);
$product = new product();
$product->category = $category;
That would create the relationship I believe.