And*_*ord 7 symfony doctrine-orm
我Symfony 2.8目前正在使用一个基于Web的项目Doctrine 2。该项目基本上是一个简单的待办事项列表应用程序,可以与移动应用程序(iOS / Android)同步。
阅读Doctrine 3我发现的更新说明时,EntityManager::merge 将不再受支持。
ORM 3.0没有提供EntityManager#merge()的替代方法,因为合并语义应该是业务域的一部分,而不是应用程序的持久性域。如果您的应用程序严重依赖类似于CRUD的交互和/或PATCH静态操作,则应考虑使用诸如JMSSerializer之类的替代方法。
我不确定最好的/正确的替换方法是EntityManager::merge什么?
我在哪里使用合并:
在移动应用程序与Web应用程序同步期间,数据将以序列化JSON的形式传输,然后通过反序列化将其传输JMSSerializer到实体对象。当Web应用以ToDoEntry这种方式接收对象时,它可以是新的ToDo-Entry(Web应用中尚不知道)或更新的现有条目。无论哪种方式,接收到的对象都不由进行管理EntityManager。因此$em->persist($receivedObject)将始终尝试插入一个新对象。如果Web应用程序中已经存在ToDo-Entry并且需要更新,则失败(由于id的唯一约束)。
而是$em->merge($receivedObject)使用它自动检查是否需要插入或更新。
热点解决了吗?
当然,如果已经存在具有相同ID的实体,我可以检查每个接收到的对象。在这种情况下,可以加载现有对象并手动更新其属性。但是,这将非常麻烦。实际的项目当然会使用许多不同的实体,并且每个实体类型/类都需要使用自己的处理方法来检查哪些属性需要更新。有没有更好的解决方案?
虽然我很久以前就已经发布了这个问题,但它仍然很活跃。到目前为止,我的解决方案是坚持使用 Doctrine 2.9 并继续使用该merge函数。现在我正在开发一个新项目,该项目应该已准备好 Doctrine 3,因此不应merge再使用它。
我的解决方案当然是针对我的特殊用例的。然而,也许它对其他方面也有用:
正如问题中所述,我使用该merge方法将反序列化的外部实体同步到 Web 数据库中,其中该实体的版本可能已经存在(需要更新)或不存在(需要插入)。
在我的例子中,实体具有不同的属性,其中一些属性可能与同步相关并且必须合并,而其他属性仅用于(网络)内部管理并且不得合并。为了告诉这些属性,我创建了一个自定义@Merge注释:
use Doctrine\Common\Annotations\Annotation;
/**
* @Annotation
* @Target("PROPERTY")
*/
final class SyncMerge { }
Run Code Online (Sandbox Code Playgroud)
然后使用此注释来标记应合并的实体属性:
class ToDoEntry {
/*
* @Merge
*/
protected $date;
/*
* @Merge
*/
protected $title;
// only used internally, no need to merge
protected $someInternalValue;
...
}
Run Code Online (Sandbox Code Playgroud)
在同步过程中,注释用于将标记的属性合并到现有实体中:
public function mergeDeserialisedEntites(array $deserializedEntities, string $entityClass): void {
foreach ($deserializedEntities as $deserializedEntity) {
$classMergingInfos = $this->getMergingInfos($class);
$existingEntity = $this->entityManager->find($class, $deserializedEntity->getId());
if (null !== $existingEntity) {
// UPDATE existing entity
// ==> Apply all properties marked by the Merge annotation
foreach ($classMergingInfos as $propertyName => $reflectionProperty) {
$deserializedValue = $reflectionProperty->getValue($deserializedEntity);
$reflectionProperty->setValue($existingEntity, $deserializedEntity);
}
// Continue with existing entity to trigger update instead of insert on persist
$deserializedEntity = $existingEntity;
}
// If $existingEntity was used an UPDATE will be triggerd
// or an INSERT instead
$this->entityManager->persist($deserializedEntity);
}
$this->entityManager->flush();
}
private $mergingInfos = [];
private function getMergingInfos($class) {
if (!isset($this->mergingInfos[$class])) {
$reflectionClass = new \ReflectionClass($class);
$classProperties = $reflectionClass->getProperties();
$propertyInfos = [];
// Check which properties are marked by @Merge annotation and save information
foreach ($classProperties as $reflectionProperty) {
$annotation = $this->annotationReader->getPropertyAnnotation($reflectionProperty, Merge::class);
if ($annotation instanceof Merge) {
$reflectionProperty->setAccessible(true);
$propertyInfos[$reflectionProperty->getName()] = $reflectionProperty;
}
}
$this->mergingInfos[$class] = $propertyInfos;
}
return $this->mergingInfos[$class];
}
Run Code Online (Sandbox Code Playgroud)
就是这样。如果将新属性添加到实体中,我只需决定是否应合并它,并在需要时添加注释。无需更新同步代码。
| 归档时间: |
|
| 查看次数: |
609 次 |
| 最近记录: |