How to set parent_id=NULL in child table when record in parent table is deleted? - atk4

How to set parent_id=NULL in child table when record in parent table is deleted?
It's like ON DELETE = SET NULL in MySQL INNODB tables, but I would like to avoid using all this (cascading, ignoring, updating and setting null) functionality in INNODB level and move it to atk4 Model to keep all this in logic one place.
For example,
class Model_Parent extends Model_Table{
public $table='parent';
function init(){
parent::init();
$this->addField('name');
$this->hasMany('Child');
$this->addHook('beforeDelete',$this);
}
function beforeDelete($m){
// I guess here I should somehow set parent_id=NULL in all related Model_Child
// records, but when I do so, then it's again DB constraint violation of course
$c = $m->ref('Child');
foreach($c as $junk){
$c->set('parent_id',NULL); // this and below is not working
$c->save();
}
}
}
class Model_Child extends Model_Table{
public $table='child';
function init(){
parent::init();
$this->addField('name');
$this->hasOne('Parent');
}
}

It's simple, you just need to go into DSQL from Model:
$m->ref('Child')->dsql()->set('parent_id',null)->update();
More info: http://www.youtube.com/watch?v=sSRaYpoJFHk&list=PL7CBF92AB03A1CA3B&index=3&feature=plpp_video

You are trying to re-invent the wheel by doing a typical database task in your code.
If you don't want the database to manage the foreign key relations, you shouldn't use those relations. In that case you can set your columns to NULL or any other value. But no one could prove the consistency of your database.

Check if parent_id column permits NULL values.

Related

How to retrieve a model and it's relationship as a single Array or Object | Eloquent, Eloquent: Relationships

i have 3 tables with one-to-one relationship. The phone table has one to one relationship with Model table and Model table has a one to one relationship with Manufacturer table.
phone_table
id
imei
image
model_id
model_table
id
name
image
manufracturer_id
manufracturer_table
id
name
logo
how to get a result like this :-
App\Phone{
imei : "356554512522148",
model : "Galaxy S-10",
manufracturer : "Samsung",
}
I would never throw it into the same array / object, i would firstly do that on transformation. If you use default Laravel transformation you can use getters for it. Simple example on how to access these fields into the same context would be.
$phone = Phone::with('model.manufactor')->find(1);
With secures the queries are optimal for accessing it. How to get data into same layer.
[
'imei' => $phone->imei,
'model' => $phone->model->name,
'manufactor' => $phone->model->manufactor->name,
]
For this to work, you need relations in your model too.
Phone.php
public function model()
{
return $this->belongsTo(Model::class);
}
Model.php
public function manufactor()
{
return $this->belongsTo(Manufactor::class);
}
Just join them:
\App\Phone::leftjoin('model_table AS mo', 'mo.id', '=','phone_table.model_id')
->leftjoin('manufracturer_table AS ma', 'ma.id', '='. 'mo.manufracturer_id')
->selectRaw('phone_table.imei, mo.name AS model, ma.name AS manufracturer')
->first()
And sometimes you need to think about why you want to split table to one-to-one relationship.
Is there a table not usually be used, or one of them need to be connected by another tables. is this just for saving space or reduce IO cost.
If there are not any other reason and you always need to get these tables' information, maybe you can merge to one table.

How to generate gii crud Yii2 without Primary Key?

How can i generate the crud wihtout primary key because, my dabatase, this table don't have a primary key. there is FK only.
when i try to generate it will be like this
image.
Thank you for your help.
I think, it is not very good to use CRUD without PK. But, if there are no other options, you can add fake PK variable to table temporarily and after generation delete that. You should change some code to escape errors on generated files (controller and views) to remove references to that fake variable. And you should be more careful, because, you could update or delete some other record instead needed one
Update
Assuming that the DB structure is like this one and you should generate CRUD for the table 'othertable', you can:
add PK as "id" to the table
regenerate model "Othertable"
generate CRUD for "othertable"
Remove id from table
Regenerate "Othertable"
Add these lines to "Othertable":
//imitate id
public $id;
//rediclare init
public function init() {
parent::init();
$this->id= $this->sometable_id;
}
// Rediclare primary key. For this condition sometable_id
// have chosen as primary
// key. We can change it
public static function primaryKey() {
return ['sometable_id'];
}
Remove id from OthertableSearch model
Change findModel($id) method on OthertableController as:
protected function findModel($id)
{
if (($model = Othertable::find()->where(['sometable_id'=>$id])->one()) !== null) {
$model->id=$model->sometable_id;
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
Attentions
In this example I used sometable_id of the "othertable" assuming that there is only one record on the table with this sometable_id value (a.g. unique), otherwise every time you can get first record and change/delete that instead needed one. It can be changed to other unique variable(s) of the table. If you want use other variable, you should change on model and on findModel() method of the controller.

Retrieving data from referenced key table - Laravel-4

The structure of concerning tables is as follows (MySQL):
//Table Name : team
tid PK
team_name (varchar)
//Table Name : fixture
fid PK
home_team_id FK |_ both referenced to 'tid' from 'team' table
away_team_id FK |
My aim is to retrieve the team names. Considering this structure, I think I'll have to retrieve home_team_id and away_team_id and then do something like
Fixture::where('tid','=',$home_team_id)->get();
My question is, is this the correct way to accomplish what I aim to do?
and
should this be done from the controller? (if so, then I'll have to do two queries from same function)
First, rather than having your primary keys be tid and fid, just keep them both as id. This is not only best practice, but will allow you to more easily use Laravel's Eloquent ORM as it by default assumes your primary key column is named id.
Second thing, make sure your table names are in plural form. Although this is not necessary, the example I'm about to give is using Laravel defaults, and Laravel assumes they are in plural form.
Anyway, once you've 'Laravelized' your database, you can use an Eloquent model to setup awesome relationships with very minimal work. Here's what I think you'd want to do.
app/models/Team.php
class Team extends Eloquent {
// Yes, this can be empty. It just needs to be declared.
}
app/models/Fixture.php
class Fixture extends Eloquent {
public function homeTeam()
{
return $this->belongsTo('Team', 'home_team_id');
}
public function awayTeam()
{
return $this->belongsTo('Team', 'away_team_id');
}
}
Above, we created a simple model Team which Laravel will automatically look for in the teams database table.
Second, we created model Fixture which again, Laravel will use the fixtures table for. In this model, we specified two relationships. The belongsTo relationship takes two parameters, what model it is related to, in both cases here they are teams, and what the column name is.
Laravel will automatically take the value in away_team_id and search it against the id column in your teams table.
With just this minimal amount of code, you can then do things like this.
$fixture = Fixture::find(1); // Retrieves the fixture with and id of 1.
$awayTeam = $fixture->awayTeam()->first(); // var_dump this to see what you get.
$homeTeam = $fixutre->homeTeam()->first();
Then you can proceed as normal and access the column names for the tables. So say you have a 'name' column in the teams table. You can echo out the the home team name from the fixture like so.
$fixture = Fixture::find(1); // Get the fixture.
echo $fixture->homeTeam->name;
It's nearly 2AM, so there might be an error or two above, but it should work.
Make sure you check the docs for Eloquent, especially the bits relating to relationships. Remember to name your columns and tables in the way Laravel wants you to. If you don't, there are ways to specify your custom names.
If you want to get even more fancy, you can define the inverse relationship like this on your Team model.
app/models/Team.php
class Team extends Eloquent {
public function fixturesAtHome()
{
return $this->hasMany('Fixture', 'home_team_id');
}
public function fixturesAway()
{
return $this->hasMany('Fixture', 'away_team_id');
}
}
Then to get all of a particular team's home fixtures...
$team = Team::find(1); // Retreive team with id of 1;
$homeFixtures = $team->fixturesAtHome();

grails one to many relationship: no entries created on database

I have two domain classes in which one has a one to many relationship with the other
Class A
{
...
#NotNull
static hasMany = [bElements:B]
}
Class B
{
...
}
When I run the application, the relation table A_B is created and entries in A_B table are automatically added when user creates A objects. Then I've decided to change this relation, because I've noticed that it is better to have a relation between class A and class C, so class A now has
static hasMany = [cElements:C]
but when I create a new object of type A (after creation of some C objects), adding one or more objects of type C, in my database I don't see the entry into the A_C table, but only in A table.
Why do this beahavior happens? What must I control to resolve problem?
EDIT:
maybe it is needed some clarifications. The Class A is a class that describes an invoice and the class C is a class that describes the invoices items. So I need to give a one-to-many relationship between this two classes, but as described above, it does not work as expected...
EDIT 2:
I've noticed that maybe the problem depends on the fact that the field cElements in A object is null. In the view, I've described the cElements field as follows:
<g:select name="receiptItems" from="${HealthService.findAllByDoctor(Doctor.findBySecUser(new ReceiptController().getCurrentlyLoggedUser()))}"
multiple="multiple" optionKey="id"
optionValue="${{it.healthServiceType.healthService}}"
size="5" value="${receiptInstance?.healthServices*.id}" class="many-to-many"
onchange="${remoteFunction(
controller: 'Receipt',
action: 'sumReceiptItems',
params: '\'receiptItemsSelected=\' + jQuery(this).val()',
onSuccess: 'updateTotalAmount(\'totalAmount\', data, \'00000\')')}"/>
It is a multiple select. After each selection, with the remoteFunction, a method from controller is called to do some calculation and update the totalAmount field. It works well but, when save method is called, healthServices field is null...and I don't understand why...I will open another post to solve this issue (solved here)
If you declare a class like
Class A
{
...
#NotNull
static hasMany = [cElements:C]
}
Class C
{
static belongsTo= [a:A]
...
}
In this case it does not create A_C but if you declare it like
Class A
{
...
#NotNull
static hasMany = [cElements:C]
}
Class C
{
//no belongTo
...
}
then it creates A_C in database to map these fields id.
There is no need to have an intermediate table with A-B relations when you have one-to-many relation esablished. If relation was bidirectional (B class objects could have multiple A class objects) then the intermediate table would be useful.
Check your databse whether your B class objects contain pointers (foreign keys) to A class objects. If they do, your ORM decided to create one-to-many relationship and your A-B relations table is not used.
I would ditch the intermediate table for now and add the following to B class
static belongsTo = [parent:A]
(keep the hasMany in A):
This will create a bi-directional relationship from B to A (aka foreign key in B table). Make sure you are conscious of how cascading deletes are handled with belongsTo.
http://grails.org/doc/2.2.x/ref/Domain%20Classes/belongsTo.html
You mentioned pre-populating. Make sure you aren't violating any constraints. Bootstrap often fails silently. Add something like on your instance in question:
`
if (!b.save()) {
b.errors.each {
println it
}
}
`
After you get this relationship working, take a look at this talk if you need to refactor your relationship for gorm performance using an intermediary table. http://www.infoq.com/presentations/GORM-Performance

Entity Framework 4.0 Many-Many relationship Using Non-Primary Key

I am trying to build a generic repository using Entity Framework 4.0 using a legacy MS SQL database I have inherited. A pretty familiar scenario.
I need to add category information to a fairly long list of existing items.
The items can belong to several categories at the same time so I created an mapping table called CategoryMapping
Unfortunately SchemaDefinitionCode is not unique and cannot be made into a Foreign Key (FK) in the database.
I have tried to add my own partial class to the DefinitionSchema entity but as it's not indexed, this has a severe performance hit. Demo code for testing, I won't want to create a new context every time I load this:
public partial class DefinitionSchema
{
private MyEntities context;
public IQueryable<Category> Categories
{
get
{
context = new MyEntities();
var categories = context.Categories
.Where(c => c.CategoryMappings
.Where(m => m.SchemaDefinitionCode == this.SchemaDefinitionCode).Any());
return categories;
}
}
}
I can then call a list of items like so:
var q = context.SchemaDefinitions
.Where(s => s.Categories
.Where(c => c.Name == category)
.Any()
);
How can I link my tables and mapping in the most efficient manner without wiping out the existing database structure?
It can't work this way because EF doesn't support unique keys and SchemaDefinitionCode must be unique to form valid many-to-many relation with Category. If your SchemaDefinitionCode is not unique in DefinitionSchema table it can't be used as principal end in the relation with CatagoryMapping. If it is unique you can use SchemaDefinitionID instead because no more then one Id will have the same code value.

Resources