Possible to Fix a Foreign Key in Yii without having set it up in the Database? - mysql

I'm using phpMyAdmin for my database GUI and it's connecting to Yii Framework on my website.
I wish for my products table for instance, to have a foreign key department_id which is a reference to the id field of my departments table. Unfortunately, I don't currently have the facility to set the foreign key up properly in phpMyAdmin, so department_id is just an indexed field. I cannot change the configuration of phpMyAdmin at the moment so it's stuck like it is without a foreign key and relationship facility.
Is there a way to modify the Models of these tables in Yii so they link? I know there is a relations function inside the Model Class file that holds this information:
return array('department_id' => array(self::BELONGS_TO, 'Departments', 'id'),
Could I not just add something similar to the above? Is there more legwork? Is it now fixed (as in static, not corrected) because of phpMyAdmin?
Cheers

If I'm not mistaken, you don't need to have mySql enforcing foreign key relationships for them to still work in Yii. Setting up FK constraints in mySql ensures proper database integrity, but I don't think Yii actually uses that at runtime.
When initially running yiic (of Gii) to build the project I think it looks at the DB to build the right relations in the Model, but it doesn't use them after that.
Yii then uses this knowledge (from yiic) of the table relationships to make your life easier by providing shortcut methods to access relational data, and to ensure you don't violate mySql constraints and get ugly SQL errors, etc. But you can still use Yii relation logic without the underlying SQL constraints. The only problem will be that if Yii messes up and assigns a non-existing FK or something, your database will not catch this error (your data integrity will be more error prone).
To link your products to departments, just make sure you have a department_id field in the Product (which it sounds like you do). Then add a relation rule like so to Product:
'department' => array(self::BELONGS_TO, 'Department', 'department_id'),
And in your Department model:
'products' => array(self::HAS_MANY, 'Product', 'department_id'),
Now you should be able to use the relation like normal:
$myProductModel->department; // returns the model of the Department referenced
$myDepartmentModel->products; // returns the models of all Products in the department
Good luck, and let me know if I am way off base and it doesn't work for you!

Related

Best approach for migrating the "wrong" foreign key to the "correct" foreign key?

For context, I have a Laravel 6 project which made a rather odd choice, to put it mildly, on how to manage relationships when I inherited it.
I have a user object which has it's usual autoincrement id, as well as a "system_id" which is provided by an external system.
For most of the project, relationships involving a user object make use of their "id" field as the foreign key in the belongsTo() part of the relationship which is all well and good.
However, one many-to-many relationship, specifically the one used for the relationship between a user model and a group model, uses the user model's "system_id" field as the foreign key instead of the usual "id" field used everywhere else which is beginning to cause all kinds of development headaches, and is already in production.
So as part of a cleanup project of the system, I intend on migrating the pivot table to use the user model's "id" field. The challenge now is the following:
In a database-agnostic way, how to copy the matching id to the "user_id" foreign key field in the pivot table given a known "system_id".
How will it look in a migration? Is a migration even a good option or should it be done directly in the database instead?
Anything else I should account for?
Is this even a good idea in the first place or should we just live with it?
Obviously, a backup will be made and the whole thing will be tested in a test environment first before it's attempted in production.

How to create an IS_A relationship using Microsoft Access Relationships Tool

I was unable to find a clear answer of how to create an IS_A relationship in Access.
There was the same question here, but without a concise answer:
IS_A relationship primary key validation rules
I have the entity Employee, and two sub-entities Loan_Officer and Branch_Manager. It's a school example of an IS_A relationship really.
I've managed to create A relationship, but there needs to be a constraint that an employee must be either a Loan Officer or a Branch Manager, but can not be both. Now, I can't figure out how to do this, because what ever I do, I can assign the same Employee_ID in both sub-entity tables at once.
I've connected the tables via the PK, as it's shown here:
Now, this table design is just something I've done, in order to be able to connect them via a one-to-one relationship. I had to set the PK of Loan_Officer to "Number" and not "AutoNumber", in order to be able to connect them. The other option is to have a separate PK in Loan_Officer, like "Loan_Officer_ID", and a foreign key, "Employee_ID" in the Loan_Officer table, but the results are again the same (also according to the ER Diagram, the sub-entities don't have a separate PK).
You can't. This is not a feature of the Access database.
You can create CHECK constraints to check for such conditions, but those don't offer features to cascade operations.
See this answer for an example on how to create a CHECK constraint.
There is no such thing as an 'Is A' relationship in databases between tables. This is instead a field in the Employee table or Employee History Table.
The issue of 'can't be both' is a matter of validation logic. Where this validation logic is applied is probably at the form object level (during data entry), not the table level (no data should ever be entered directly into tables by end users).
Look into Access Data Macros . They can be used like SQL triggers firing off when a record is INSERTed, UPDATEed, DELETEed etc.

Laravel 5.3, MySQL, proper foreign key setup in migrations (one to many, many to many)

what is the proper way to setup the foreign key restrains in following scentarios.
Let say I have models Post, User, Tag.
At the moment my migrations are all set simply as:
For Comment model:
$table->integer('posts_id')->unsigned(); //comment must belong to a post
$table->integer('user_id')->nullable()->unsigned(); //comment can belong to an user
$table->integer('something_id')->unsigned(); // each Something model will have at most 5 to 10 comments in it - this is what is called cardinality if I got it right so the average cardinality is 7.5
and let's say for a many to many relation I have a pivot table between Posts and Tags as:
$table->integer('post_id')->unsigned(); //connecting the post
$table->integer('tag_id')->unsigned(); //connecting the tag
Now I need to index the fields so when my db queries are executed they're executed as fast as possible.
What I would do now is create new migration as:
$table->foreign('posts_id')->references('id')->on('posts');
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('something_id')->references('id')->on('somethings');
And the same for the pivot table:
$table->foreign('post_id')->references('id')->on('posts');
$table->foreign('tag_id')->references('id')->on('tags');
My questions are:
Is this the proper way to do this, if not how should I do it instead?
Is there some restrictions, downsides or anything I should be aware of here?
Would I gain anything by doing $table->foreign('something_id')->references('id')->on('somethings'); as the cardinality here is about 7.5? Updating of comments.something_id will never happen in my app, and the ratio of "creation of new something row" to "reading related something row from comment row" would be really low 1:10^5 (rough estimate and in next row of optimizations I'll work on caching the queries so not sure how relevant this information is)
You do not need to create new migration file for defining foreign key.
$table->foreign('posts_id')->references('id')->on('posts');
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('something_id')->references('id')->on('somethings');
put those inside comment table migration file. And
$table->foreign('post_id')->references('id')->on('posts');
$table->foreign('tag_id')->references('id')->on('tags');
in pivot table migration file.

Django Foreign key in another database

I have two separate Django apps with two different databases. In APP1 I need all of the records from one table which is in APP2 DB. Beside that, one of my APP1 models has a ForeignKey which points to APP2 model, and according to docs this is not possible.
As Django does not support foreign key relationships spanning multiple databases i don't know what to do.
Official docs:
If you have used a router to partition models to different databases,
any foreign key and many-to-many relationships defined by those models
must be internal to a single database.
This is because of referential integrity. In order to maintain a
relationship between two objects, Django needs to know that the
primary key of the related object is valid. If the primary key is
stored on a separate database, it’s not possible to easily evaluate
the validity of a primary key.
As a solution I have thought of merging these two databases, so then these two APPS would use one same database. But then i would have a mess with models because APP1 needs only one table from APP2, and it doesn't need remaining models and DB tables. Also, i'm pretty sure it would make problems (conflicts) while making migrations from these two apps to the one same database.
I'm using Django DB router and this is what i've tried so far:
class Car(models.Model):
_DATABASE = "cars"
color = models.TextField(max_length=1000)
...
class Employee(models.Model):
id = models.IntegerField()
car = models.ForeignKey(Car)
...
It gives me:
django.db.utils.OperationalError: (1054, "Unknow column 'car' in 'employees'")
One DB or Two?
First question to ask your self is it really really necessary to have two different databases? More than one app using the same database is quite common in the PHP world where most people are on shared hosting and the hosting plan allows for only one database.
It's very rare for a website to have sufficient traffic to split the content between two databases. And usually the over head of the router makes it not worth the while. Sharding is almost always better handled with specialized software.
Yep it has to be two!
This is not impossible but just darned hard.
The first thing to do is to change your Car model
class Car(models.Model):
color = models.TextField(max_length=1000)
class Meta:
managed = False
Note that it no longer refers to the second database and it's unmanaged. But you don't have such a table in your database. So you need to create a view
CREATE OR REPLACE VIEW myapp_cars AS SELECT * FROM cars.otherapp_cars
Please make sure to use the exact database and table names to match your existing ones. We are only half way through. You need to create a trigger to insert into the other database. That has been discussed here many times before, so I will not elaborate. Examples
MySQL Trigger to insert data into different DB
How to create trigger to insert data to a database on another server
If you want these steps to be reproducible you will need to add a migration manually.
I thing this problem has nothing to do with django. By design DBMS doesn't allow FK between databases. Maybe you can found some workaround on internet but probable they don't adhere to best practices.
Check Cross Database Relations section at:
https://docs.djangoproject.com/en/3.2/topics/db/multi-db/
What worked for me was setting the ForeignKey db_constraint to False. This way, no constraint is created during the migration, but the correct field type is still created (from the target model's primary key). The database integrity is not enforced, so you have to know what you are doing. The ForeignKey field is indexed by Django regardless of this flag.
Example:
class Employee(models.Model):
car = models.ForeignKey(Car, db_constraint=False)
...
Docs: https://docs.djangoproject.com/en/4.1/ref/models/fields/#django.db.models.ForeignKey.db_constraint
This flag has existed at least since version 1.x, so I don't know how it didn't come up before.
Needless to say, you are sacrificing your database constraint, so if a record is deleted on the other database, you will have an invalid reference and this may cause exceptions in Django when accessing the property.
DB Router
You will also need to tell Django that you allow relations between databases. You can do that by adding the following method to your router class:
class MyRouter:
def allow_relation(self, obj1, obj2, **hints):
if obj1._meta.app_label == 'default' and obj2._meta.app_label == 'database2':
return True
This function should return True if the router should allow the relation, False if you want to actively deny it, and None for the default behaviour - which is allowing only relations in the same database (which is not what we want). A looser implementation would be to just allow everything (return True).
Docs: https://docs.djangoproject.com/en/4.1/topics/db/multi-db/#allow_relation

Best Way to Handle Zero to One (Optional) Foreign Key Relationships in MySql

Not sure if this is possible... however I have a table called "LineItems" with a column called "PackageId" -> PackageId IS optional, however i'd still like to somehow setup a foreign key relationship to its relating table Packages - is this possible? If so how might I go about doing it
Also, I will be using the ADO.net Entity Framework Model v4 in conjunction with MySql. i would like to apply this constraint via MySQL (if possible) and have it carry into the Entity Framework model code
thanks!
Loren
I apologize for my ignorance, however I just learned that by setting a column to allow null appears to allow me to still keep the foriegn key relationship