set Doctrine2 entity property without retrieving entire associated object - doctrine-orm

I have a table Object that has 2 fields that are foreign keys (user_id and teacher_id). After generating the Entities for the X table, the entity only contain the $user and $teacher properties, which forces me to use the associated objects instead of id. So supposing I know the user_id and teacher_id for my object, instead of doing:
$object->setUserId(1)
I have to do:
$user = $this->getDoctrine()->getRepository('MyBundle:Users')->find(2);
$object->setUser($user)
is there no way to work directly with the ids to avoid retrieving the entire object associated to each id?

The framework suggests to use objects when setting the association value. Still – are you sure the record isn't loaded in the memory already? If it is, it will not cause additional SQL statement execution.
If you really need to update the association without loading the object, you can
run native SQL;
try creating Doctrine Proxy object manually and setting it instead.
You can get the proxy object using EntityManager method getReference:
$object->setUser($this->getDoctrine()->getReference('MyBundle:Users', 2));

Related

Doctrine ORM how to save an UPDATE of my object to the database (equivalent of SQL UPDATE query)

I'm new to Doctrine and I can't seem to find an answer to this.
To save a newly created object to the database (equivalent of SQL INSERT query), I'm using
$this->getEntityManager()->persist($category);
$this->getEntityManager()->flush($category);
And to delete one (equivalent of SQL DELETE query), I'm using
$this->getEntityManager()->remove($category);
$this->getEntityManager()->flush($category);
Now, how do I save updates to my $category object to the database? I'm looking for the Doctrine equivalent of an UPDATE query.
Surely Doctrine ORM must have a simple method to do this, without having to use DQL?
Well there is no need for specific update query.
With doctrine you can update objects like this. Let's suppose you have category object with field name. So we will try to update it.
$newName = 'hello world';
$category->setName($newName);
$this->em->flush(); // without passing the object
This will update you entity.
So following up from this, we have learnt, that you can update entities, by just using setters and setting new values, and after that you flush. It will handle things automatically.

how to build a vapor app from an already existing database?

I have built a MySQL database with multiple tables and complex relationships, but when I go through the vapor documentation, specifically, in the building the model phase, there is a method for creating the table (that my model class will interact with).
static func prepare(_ database: Database) throws {
try database.create("users") { users in
users.id()
users.string("name")
}
}
However, I don't want to use it because the table that I already have contain foreign keys and types like DATETIME (which I don't know how to declare within the swift context.) is there a way to link my already built tables with vapor?
This is somewhere Vapor (or more correctly Fluent, which is the database level of Vapor) is a bit limited.
Yes, you can use your existing tables. In your prepare(_:) method, you can simply leave the implementation empty without creating a table at all. You should also leave revert(_:) empty as well.
In your init(node:in:) initialiser and makeNode(context:) method, you will need to map between the column names and types in your table and the property types in your Swift model.
In the model object class (User here), the prepare method can be left unimplemented since we don't need to create the tables explicitly from the code. So should be like
static func prepare(_ database: Database) throws {
...
}
But should add a static variable named entity which will map the table name in db without model class, like following
final class User: Model {
static let entity = "users"
...
}
And finally, we should add the model to the droplet's preparations array with drop.preparations.append(User.self)
So that we can use any existing table in a database which has complex relationships, to map from a model object in Vapor.

how to make a relation from several objects/tables with a relation to common objects/tables

I am using django and have three objects: Customer, Location and Department. Each has a related Setting object.
Is it better form to create a single table with optional/null foreign keys?
Or to create a different setting object/table for each of the 3 entities?
There are a few options
Create a separate Settings table and have a nullable ForeignKey from all of your objects to the Settings table. If you choose this option, you should create an abstract base class that has a ForeignKey to the Settings table and inherit from that abstract base class. That way you don't have to add the ForeignKey every time you create a new model.
Create a separate Settings table and use GenericForeignKeys from the Settings table to reference your object (Customer, Location, and Department). This has the advantage of not having an extra column in all of your tables that need settings. However, you can't do DB joins with GenericForeignKeys via the Django ORM's normal API. You'd have to use raw sql. Also, select_related doesn't work on GenericForeignKeys so you'd have to use prefetch_related instead.
Store the settings in a column in the database. You should interact with the data in some format (I like JSON) and then serialize it to a string to store in the DB. Then to read the settings, you could deserialize the string back into JSON and interact with it. With this method, you wouldn't need to join with another table to get settings, and wouldn't need to run migrations every time you added new settings. You also wouldn't need a separate Settings table. However, constructing a query to find objects with certain settings would be a pain the query would probably be slow as well.
Each option has its pros and cons; so, pick your poison ;)

Doctrine 2 How do I add a record to a join table that has no entity?

Having a hard time wrapping my head around this one. I have a Page entity and a Keyword entity. I've created a member variable called $keywords in my Page entity that has a ManyToMany association that creates a join table called "pages_keywords". In my application, I want to give the ability to add a keyword to a page. How would I go about adding that record to the database?
I can access the Page entity's $keywords member variable but I'm not sure where to go from there. I see that the Doctrine implementation of ArrayCollection has an add() method that just takes a value. Can I just pass it the Keyword entity's id and will that create the record for me?
Assuming you know the primary key value of the entity you are looking to associate it with (in your example, the $keywordId), the best way to do this is to get a reference to the entity. This gets you a reference without doing a database lookup for the associated entity.
The solution you posted in your follow-up answer has the disadvantage of requiring an extra trip to the database to retrieve the keyword record. Retrieving it as a reference means that there is no extra database lookup:
<?php
// assumes $this->em is already defined as the Doctrine2 EntityManager
$page = $this->em->getRepository('App\Entity\Page')->find($pageId);
// associate $keyword with $page via a reference to the keywordId
$keyword = $this->em->getReference('App\Entity\Keyword', $keywordId);
$page->getKeywords()->add($keyword);
$em->flush();
I seem to answer a lot of my own questions for some reason. :)
Figured this one out. I just grab my Page object and the Keyword object I want to add to tha page, then get the keywords and use the add() method passing in the keyword object.
// Assuming you have an instance of the Entity Manager
$page = $this->em->getRepository('App\Entity\Page')->find($pageId);
$keyword= $this->em->getRepository('App\Entity\Keyword')->find($keywordId);
$page->getKeywords()->add($keyword);
$em->persist($page);
$em->flush();

mongoid new versus build

why mongoid dosen't insert id when calling new on an association, but inserts id when calling build on an association?
Is this a bug or this is how it works in mongoid?
this is the same behaviour your get with other ORMs, e.g. SQLite ... #new does not create an ID because the new object hasn't been saved / persisted yet!
Whenever a save happens, the next available ID is used for the newly saved object... that means if you had a couple of new objects, you could not assign them an ID until they are saved, because the ID depends on the order they are saved in..
MongoDB IDs are not incremented as IDs in SQL DBs, but they contain a time stamp as part of the key.. hence again the dependency on the order of saving / persisting the objects
Also: the IDs only make sense as a reference to saved objects -- you could create objects with #new and end up not saving them -- it would not make sense to assign an ID to an un-saved object.