I have a pre-existing Oracle database that I want to exploit.
To do this, I created 2 classes that I map with many-to-one and one-to-many. But there are elements of which the first class have no correspondence in the second class, however id exists. It does not return any error.
I would like that it sends me rather a null. How to do that ?
class Fact
{
/**
*
* #ORM\OneToMany(targetEntity="present\UserBundle\Entity\March",mappedBy="fact", cascade={"persist","remove"})
*/
private $march;
}
class March
{
...
/*
* #var \present\PublishBundle\Entity\image
* #ORM\ManyToOne(targetEntity="present\UserBundle\Entity\fact",inversedBy="march", cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id",referencedColumnName="id")
* })
* })
*/
private $facture;
}
the error
Entity of type 'present\UserBundle\Entity\Client' for IDs id(0) was not found
Thanx you
I haven't tested your code but I think your error has to do your JoinColumn declaration :
#ORM\JoinColumn(name="id",referencedColumnName="id")
In the documentation here it says that the name attribute will define the name of the column for your relation.
But here "id" is also referencing to your primary key I suppose.
To solve it, try to change the name="id" by name="march_id", or remove the JoinColumn.
Edit : I have read a bit to quickly the error, haven't seen it's referencing to Client entity, can you show the code related to this relation too ?
Related
Working my way through the levels of PHPStan with a new applicaton, I got to level 3 and started getting error messages from all my test fixtures for models. The basic format is as follows:
------
Line tests/TestCase/Model/Table/UsersTableTest.php
------
43 Property Visualize\Test\TestCase\Model\Table\UsersTableTest::$Users (Visualize\Model\Table\UsersTable) does not accept Cake\ORM\Table.
------
The code that this error refers to is:
/**
* setUp method
*
* #return void
*/
public function setUp(): void
{
parent::setUp();
$config = $this->getTableLocator()->exists('Users') ? [] : ['className' => UsersTable::class];
$this->Users = $this->getTableLocator()->get('Users', $config);
}
This setup code was build using cake bake, so I'm not sure what it's looking for. Does anyone else know what will resolve this issue for me?
EDITED: I did a bit of further searching. The only version of the getTableLocator() function I could find associated with this stack was in the TableRegistry class. That class in turn has a function called get() and that function does indeed return an object of type \Cake\Orm\Table:
/**
* Get a table instance from the registry.
*
* See options specification in {#link TableLocator::get()}.
*
* #param string $alias The alias name you want to get.
* #param array $options The options you want to build the table with.
* #return \Cake\ORM\Table
* #deprecated 3.6.0 Use {#link \Cake\ORM\Locator\TableLocator::get()} instead. Will be removed in 5.0.
*/
public static function get(string $alias, array $options = []): Table
{
return static::getTableLocator()->get($alias, $options);
}
So does this mean my tests ought to expect the \Cake\ORM\Table class? TBH, I've yet to do much of anything in the way of testing Models (as you might have guessed), thus I'm not sure the consequences of doing that.
The question is how to deduce from $this->getTableLocator()->get('Users', $config); that it should be returning Visualize\Model\Table\UsersTable.
You can write a dynamic return type extension if you come up with logic that can deduce that from the abstract syntax tree and maybe other places like configuration.
It's possible that the extension https://github.com/CakeDC/cakephp-phpstan might already tackle that, this class definitely looks like that: https://github.com/CakeDC/cakephp-phpstan/blob/master/src/Type/TableLocatorDynamicReturnTypeExtension.php
I wanted to know if the {save} method in CrudRepository do an update if it finds already the entry in the database like :
#Repository
public interface ProjectDAO extends CrudRepository<Project, Integer> {}
#Service
public class ProjectServiceImpl {
#Autowired private ProjectDAO pDAO;
public void save(Project p) { pDAO.save(p); } }
So if I call that method on an already registred entry, it'll update it if it finds a changed attribute ?
Thanks.
I wanted to know if the {save} method in CrudRepository do an update
if it finds already the entry in the database
The Spring documentation about it is not precise :
Saves a given entity. Use the returned instance for further operations
as the save operation might have changed the entity instance
completely.
But as the CrudRepository interface doesn't propose another method with an explicit naming for updating an entity, we may suppose that yes since CRUD is expected to do all CRUD operations (CREATE, READ, UPDATE, DELETE).
This supposition is confirmed by the implementation of the SimpleJpaRepository
class which is the default implementation of CrudRepository which shows that both cases are handled by the method :
#Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
So if I call that method on an already registered entry, it'll update
it if it finds a changed attribute?
It will do a merge operation in this case. So all fields are updated according to how the merging cascade and read-only option are set.
Looking at the default implemantation of CrudRepository interface
/*
* (non-Javadoc)
* #see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
*/
#Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
Save method manage two situations:
-If the person Id is null (a new entity is created) then save will call persist method => insert query will be executed.
-If the person id is not null then save will call merge: fetch the existing entity from entityManagerFactory(from the 2 level cache if it doesn't exist then it will be fetched from the database) and comparing the detached entity with the managed and finally propagate the changes to the database by calling update query.
To be precise, the save(obj) method will treat obj as a new record if the id is empty (therefore will do an insert) and will treat obj as an existing record if the id is filled in (therefore will do the merge).
Why is this important?
Let's say the Project object contains an auto-generated id and also a person_id which must be unique. You make a Project object and fill in the person_id but not the id and then try to save. Hibernate will try to insert this record, since the id is empty, but if that person exists in the database already, you will get a duplicate key exception.
How to handle
Either do a findByPersonId(id) to check if the obj is in the db already, and get the id from that if it is found,
Or just try the save and catch the exception in which case you know it's in the db already and you need to get and set the id before saving.
I wanted to know if the {save} method in CrudRepository do an update if it finds already the entry in the database:
The Answer is Yes, It will update if it finds an entry:
From Spring Documentation: Herehttps://docs.spring.io/spring-data/jpa/docs/1.5.0.RELEASE/reference/html/jpa.repositories.html?
Saving an entity can be performed via the CrudRepository.save(…)-Method. It will persist or merge the given entity using the underlying JPA EntityManager. If the entity has not been persisted yet Spring Data JPA will save the entity via a call to the entityManager.persist(…)-Method, otherwise the entityManager.merge(…)-Method will be called.
In my case I had to add the id property to the Entity, and put the annotation #Id like this.
#Id
private String id;
This way when you get the object has the Id of the entity in the database, and does the Update operation instead of the Create.
My situation is this, firstly there is a entity Person which have a OneToMany relationship with the entity Face (and of course the other way around with ManyToOne), and each time I update the Person entity I might add some extra Face entities to the Person. Basically it looks like this:
/**
* #ORM\OneToMany(targetEntity="Face", mappedBy="person", cascade={"persist"})
*/
private $faces;
...
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
foreach ($this->images as $image) {
if (null === $image) {
break;
}
$face = new Face();
$face->setPerson($this);
$face->setImagePath(sha1(uniqid(mt_rand(), true)));
$this->addFace($face);
}
}
This works as expected when I do persist the Person with some Face entities for the first time, but when I try to update a existing Person and add more Face entities I cannot make them persist, everything that should happen does, except that no new Face entities is persisted.
Hope somebody has been in the same situation and can give me some advice, peace out!
I have a comparable project, where a survey has questions and each Question has an Image.
I followed the docs here and for updating the related entity I moved all the logic to that Entity, which wuold be "Face" in your case. Everything works fine and my controller looks like this:
...
$survey->preUpload();
$questions = $survey->getQuestions();
foreach ($questions as $question)
{
$question->preUpload();
}
$em->persist($survey);
$em->flush();
...
Hope that helps.
You need to specify a cascade persist policy even on the other side of the relation. It's not automatically bidirectional.
/**
* #ORM\ManyToOne(targetEntity="Person", inversedBy="faces", cascade={"persist"})
*/
I'm running into a severe problem, In fact I'm not well understanding recess naming convention for relationship. I personally think it should be more documented with concrete examples. Hopefully, if i get to understand it, I can start to write some examples.Also, if someone has well understand Recess relationship convention well, in case, he can explain it here, it would be great
I have two table, all table names are in the database are the lower case of the model names. All fields names are same to the models' attributes
Post---->Comment(A Post can have several comments)
Model Post:
<?php
/**
* !Database Default
* !Table post
* !HasMany comment, Class:try.models.Comment,Key:postId
*/
class Post extends Model
{
/** !Column PrimaryKey, Integer, AutoIncrement */
public $postId;
/** !Column String */
public $name;
}
?>
Model Comment:
<?php
/**
* !Database Default
* !Table comment
* !BelongsTo post
*/
class Comment extends Model {
/** !Column PrimaryKey, Integer, AutoIncrement */
public $commentId;
/** !Column String */
public $name;
}
?>
However, when I'm doing the following, I'm getting an error
<?php
Library::import('try.models.Post');
Library::import('try.models.Comment');
Library::import('recess.framework.controllers.Controller');
/**
* !RespondsWith Layouts
* !Prefix Views: home/, Routes: /
*/
class TryHomeController extends Controller {
/** !Route GET */
function index()
{
$this->flash = 'Welcome to your new Recess application!';
$Post= new Post(5);
$Comments=$Post->comment();
}
}
?>
However, I'm getting this error
try.models.Comment has not been imported.
Look in your Post model at the Class line
**
* !Database Default
* !Table post
* !HasMany comment, **Class:try.models.Comment**,Key:postId
*/
Here you are including the full classpath, try.models.Comment. You only need to specify Comment as the class to include. Be sure that your file names follow the ClassName.class.php convention.
I have a simple question about the (by the way really great!) Doctrine ODM.
Assume you have a document like:
/**
* #Document
*/
class Test
{
/** #Id */
public $id;
/** #WHICHTYPE */
public $field = array();
}
Now i want to store an associative array like
array("test" => "test1", "anothertest" => "test2", ......);
In the $field property of that class.
No problem for MongoDB, I know, but in Doctrine when I use for example #Collection or simply #Field, only the values are stored (array_values is being used in the mapping driver for collection for example). So the stored value looks like
array("test1", "test2", ....)
Does anyone know which Doctrine-ODM mapping type I should use in order to preserve the key-value pairs in the database?
Thank you in advance,
Andi (greetz from germany)
It should be the Hash type:
http://readthedocs.org/docs/doctrine-mongodb-odm/en/latest/reference/annotations-reference.html?highlight=hash#hash
For versions before ODM 2.0 #Hash will provide the necessary data type. However after ODM 2.0 #Hash field is being removed. In order to use it we have to use #field with type hash.
For further reference [click here][1]
I think you're looking for hash data type. Aren't you?
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #Document
*/
class Test
{
/** #Id */
public $id;
/**
* #MongoDB\Field(type="hash")
*/
public $field;
}
The best answer is using hash type. But if for some reason you wantn't use hash type, you can use EmbeddedDocument feature provided by Doctrine ODM like the documentation says:
If you are using the hash type, values within the associative array
are passed to MongoDB directly, without being prepared. Only formats
suitable for the Mongo driver should be used. If your hash contains
values which are not suitable you should either use an embedded
document or use formats provided by the MongoDB driver (e.g.
\MongoDate instead of \DateTime).
So, you need to create EmbeddedDocument EmbeddedExample in AppBundle\Document\EmbeddedExample.php:
<?php
namespace AppBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\EmbeddedDocument()
*/
class EmbeddedExample
{
/**
* #MongoDB\Field(type="int")
*/
protected $some_name;
// ...
// getter and setter
}
Then, you can use EmbeddedExample in your Test document. So the Test.php file will be similar to this:
<?php
namespace AppBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document(repositoryClass="AppBundle\Repository\TestRepository")
*/
class Test
{
/** #MongoDB\EmbedOne(targetDocument="EmbeddedExample") */
private $field;
// ...
}
#Array should work. At least an equivalent exists in the ORM (#Column(type="array"))