Kohana 2 ORM: ->with() for has_many relations - kohana

We have a table for articles, and a table for locale data for articles.
class Article_Model extends ORM {
protected $has_many = array('article_translations');
[...]
class Article_Translation_Model extends ORM {
[...]
'articles_translations' table contain 'article_id', 'locale_id', 'heading', 'body', etc. columns.
Is it possible to do
SELECT article.id, article_translations.heading, article_translations.body
FROM articles
JOIN articles_translations ON (articles_translations.article_id = article.id)
WHERE articles_translations.locale_id = 'en_US.UTF-8'
using Kohana 2 ORM?
The ->with() construction works only for has_one relations. The articles_translations.article_id and articles_translations.locale_id is UNIQUE, of course.

You could go the other way though:
$article_translation = ORM::factory('article_translation')
->where('locale_id', 'en_US.UTF-8')
->find();
Then you can reference the article columns as:
$article_translation->body;
$article_translation->heading;
$article_translation->article->id;

Related

How to apply filter on join table in many-to-many relation

I have many-to-many relationships between class and adventures.
So, I have 3 tables named class, adventure and class_has_adventure.
Class Table:
Adventure Table:
class_has_adventure Table:
as you can see in the class_has_adventure table I have 2 additional fields named date_start and date_stop. I want to add a filter on date_start and date-stop in the join table (class_has_adventure).
I am using Knex and Objection in my Nodejs app. I tried some methods but I didn't get results. I have used withGraphJoined, withGraphFetch and joinRelation.
Is there any way to add the filter on the join table (class_has_adventure) while querying the data from adventure or class?
We can use Knex join, in your case:
await knex.select('*')
.from('class')
.join('class_has_adventure', 'class.id', 'class_has_adventure.id_class')
.where('class_has_adventure.date_start', '>', new Date('2023-02-10'))

Is there a way to create left_table, connecting_table, right_table rows in one step using peewee

Given the following Models:
class LeftTable(Model):
left_table_col = TextField()
class Meta:
table_name = 'left_table'
class RightTable(Model):
right_table_col = TextField()
class Meta:
table_name = 'right_table'
class ConnectingTable(BaseModel):
con_table_column = TextField()
from_left = ForeignKeyField(User, backref='left_table')
to_right = ForeignKeyField(User, backref='related_to')
class Meta:
table_name = 'connecting_table'
indexes = (
# Specify a unique multi-column index on from/to-user.
(('from_left', 'to_right'), True),
)
Is there a way to create the left_table row, connecting_table row and right_table row all in one step in Peewee?
normally I'd just populate left_table, right_table and then adding a row in connecting_table using the respective ids (left_table_id, right_table_id) and additional values.
Programmer looking for a short-cut... go figure.
Unless I'm misunderstanding your question, relational databases don't have any concept of "insert into multiple tables in one operation". For this you have a different primitive: transactions.
So the proper way to do this is:
Begin a transaction
Insert into left table, right table, join table.
Commit

How do I create a Django migration for my ManyToMany relation that includes an on-delete cascade?

I'm using PostGres 10, Python 3.9, and Django 3.2. I have set up this model with the accompanying many-to-many relationship ...
class Account(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
...
crypto_currencies = models.ManyToManyField(CryptoCurrency)
After generating and running Django migrations, the following table was created ...
\d cbapp_account_crypto_currencies;
Table "public.cbapp_account_crypto_currencies"
Column | Type | Modifiers
-------------------+---------+------------------------------------------------------------------------------
id | integer | not null default nextval('cbapp_account_crypto_currencies_id_seq'::regclass)
account_id | uuid | not null
cryptocurrency_id | uuid | not null
Indexes:
"cbapp_account_crypto_currencies_pkey" PRIMARY KEY, btree (id)
"cbapp_account_crypto_cur_account_id_cryptocurrenc_38c41c43_uniq" UNIQUE CONSTRAINT, btree (account_id, cryptocurrency_id)
"cbapp_account_crypto_currencies_account_id_611c9b45" btree (account_id)
"cbapp_account_crypto_currencies_cryptocurrency_id_685fb811" btree (cryptocurrency_id)
Foreign-key constraints:
"cbapp_account_crypto_account_id_611c9b45_fk_cbapp_acc" FOREIGN KEY (account_id) REFERENCES cbapp_account(id) DEFERRABLE INITIALLY DEFERRED
"cbapp_account_crypto_cryptocurrency_id_685fb811_fk_cbapp_cry" FOREIGN KEY (cryptocurrency_id) REFERENCES cbapp_cryptocurrency(id) DEFERRABLE INITIALLY DEFERRED
How do I alter my field relation, or generate a migration, such that the cascade relationship is ON-DELETE CASCADE? That is, When I delete an account, I would like accompanying records in this table to also be deleted.
Had a closer look on this. I tried to replicate your models and I also see that the intermediary table has no cascade. I have no answer on your main question on how to add the cascade, but it seems that django does the cascade behavior which already supports this:
When I delete an account, I would like accompanying records in this table to also be deleted.
To demonstrate:
a = Account.objects.create(name='test')
c1 = CryptoCurrency.objects.create(name='c1')
c2 = CryptoCurrency.objects.create(name='c2')
c3 = CryptoCurrency.objects.create(name='c3')
a.crypto_currencies.set([c1, c2, c3])
If you do:
a.delete()
Django runs the following SQL which simulates the cascade on the intermediary table:
[
{
'sql': 'DELETE FROM "myapp_account_crypto_currencies" WHERE "myapp_account_crypto_currencies"."account_id" IN (3)', 'time': '0.002'
},
{
'sql': 'DELETE FROM "myapp_account" WHERE "myapp_account"."id" IN (3)', 'time': '0.001'
}
]
I can't find in the documentation why it is done this way though. Even adding a custom intermediary like this results in the same behavior:
class Account(models.Model):
name = models.CharField(max_length=100)
crypto_currencies = models.ManyToManyField(CryptoCurrency, through='myapp.AccountCryptocurrencies')
class AccountCryptocurrencies(models.Model):
account = models.ForeignKey(Account, on_delete=models.CASCADE)
cryptocurrency = models.ForeignKey(CryptoCurrency, on_delete=models.CASCADE)
When you use a ManyToManyField, Django creates a intermediary table for you, in this case named cbapp_account_crypto_currencies. What you want to do in the future is to always explicitly create the intermediary model, AccountCryptoCurrencies, then set the through attribute of the ManyToManyField. This will allow you to add more fields in the future to the intermediary model. See more here: https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ManyToManyField.through.
What you will now need to do is so create this intermediary table:
class AccountCryptoCurrencies(models.Model):
account = models.ForeignKey(Account)
cryptocurrency = models.ForeignKey(CryptoCurrency)
class Meta:
db_table = 'cbapp_account_crypto_currencies'
class Account(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
...
crypto_currencies = models.ManyToManyField(CryptoCurrency, through=AccountCryptoCurrencies)
You are now need to generate a migration, but do not apply it yet! Modify the migration by wrapping it in a SeparateDatabaseAndState. I havent created your migration file because I dont have the full model, but you can see here for how to do it: How to add through option to existing ManyToManyField with migrations and data in django
Now you can apply the migration and you should now have an explicit intermediary table without losing data. You can also now add additional fields to the intermediary table and change the existing fields. You can add the on_delete=models.CASCADE to the account field and migrate the change.

Deletion of a row from an association table

I am working on an app using python3 and SqlAlchemy for SQLite3 database management. I have some tables that have a Many to Many relationship. I've created an association table to handle this relationship.
Class Machine(Base):
__tablename__ 'machine'
machine_ID = Column(Integer, primary_key=True)
etc...
Class Options(Base):
__tableName__ 'options'
options_ID = Column(Integer, primary_key=True)
etc...
The association table
Machine_Options = table('machine_options', Base.metadata,
Column('machine_FK', Integer, ForeignKey('machine.machine_ID'),
primary_key=True),
Column('options_FK',Integer, ForeignKey('options.options_ID'),
primary_key=True))
All the items for the Machine and Options are inserted independently. When I want to associate a machine with an option I use an append query which works very well.
My problem is when I want to break this association between a machine and an option. I have tried a direct row deletion from the association table using a FILTER() clause on the machine_FK and the options_FK but SqlAlchemy gives me an error informing me that 'Machine_Options' table has no field 'machine_FK'.
I have tried to remove the row from 'Machine_Options' indirectly using joins with the machine and options table but received another error that I can not delete or update using joins.
I am looking for the code to only delete a row from the association table without affecting the original machine or options table.
So far my internet search has been fruitless.
The answer to my problem is to use myparent.children.remove(somechild)
The association is made using machine.children.append(option)
Using the same code as the 'append' and substituting 'remove' unmakes the association
The code:
def removeOption(machineKey, OptionKey):
session = connectToDatabase()
machineData = session.query(Machine).filter(Machine.machine_ID == machineKey).one()
optionData = session.query(Options).filter(Options. options_ID == OptionKey).one()
machineData.children.remove(optionData)
session.add(machineData)
session.commit()
session.close()

how to get eager loading in a many to many relationships?

I have a database with four tables. TableA and TableB are the main tables and the TableC is the table of the many to many relationships.
TableA(IDTableA, Name...)
TableB(IDTableB, Name...)
TableC(IDTableA, IDTableB)
This create three entities, The EntityA has an ICollection of Entity C and Entity C has a Collection of EntitiesB, so when I try to get the related entities I do this:
myContext.EntityA.Include(a=>a.EntityB.Select(b=>b.EntityC));
But this throw and exception that says that the collection is null.
So I would like to know if it is possible to do an eager loading when there are a table for the many to many relationship.
Thanks.
I think you need this:
var q = myContext.EntityC.Include("EntityA").Include("EntityB").ToList();
If you want Bs of an A:
var aId; // = something...;
var bs = from c in q
where c.EntityAId == aId
select c.EntityBId;
And simply vice versa if you need As of a B:
var bId; // = something...;
var eas = from c in q
where c.EntityBId == bId
select c.EntityAId;
With many to many association in Entity Framework you can choose between two implementations:
The junction table (C) is part of the conceptual model (class model) and the associations are A—C—B (1—n—1). A can't have a collection of Bs.
The junction table is not part of the conceptual model, but Entity Framework uses it transparently to sustain the association A—B (n—m). A has a collection of Bs and B has a collection of As. This is only possible when table C only contains the two FK columns to A and B.
So you can't have both.
You (apparently) chose the first option, so you will always have to query the other entites through C, like
from a in context.As
select new { a, Bs = a.Cs.Select(c => c.B) }
or
from a in As.Include(a1 => a1.Cs.Select(c => c.B))

Resources