我想知道在Doctrine2中使用多对多关系的最好,最干净,最简单的方法是什么.
让我们假设我们有一张专辑,如Metallica的Master of Puppets,有几首曲目.但请注意,一首曲目可能会出现在一张专辑中,比如Metal by Metallica的专辑 - 三张专辑都是这首曲目.
所以我需要的是专辑和曲目之间的多对多关系,使用第三个表和一些额外的列(比如指定专辑中曲目的位置).实际上,我必须使用,如Doctrine的文档所示,实现该功能的双重一对多关系.
/** @Entity() */
class Album {
/** @Id @Column(type="integer") */
protected $id;
/** @Column() */
protected $title;
/** @OneToMany(targetEntity="AlbumTrackReference", mappedBy="album") */
protected $tracklist;
public function __construct() {
$this->tracklist = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getTitle() {
return $this->title;
}
public function getTracklist() {
return $this->tracklist->toArray();
}
}
/** @Entity() */
class Track {
/** @Id @Column(type="integer") */
protected $id;
/** @Column() */
protected $title;
/** …Run Code Online (Sandbox Code Playgroud) 我们正在使用Doctrine,一个PHP ORM.我正在创建一个这样的查询:
$q = Doctrine_Query::create()->select('id')->from('MyTable');
Run Code Online (Sandbox Code Playgroud)
然后在函数中我添加各种where子句和适当的东西,就像这样
$q->where('normalisedname = ? OR name = ?', array($string, $originalString));
Run Code Online (Sandbox Code Playgroud)
稍后,在execute()查询该查询对象之前,我想打印出原始SQL以便检查它,并执行以下操作:
$q->getSQLQuery();
Run Code Online (Sandbox Code Playgroud)
但是,它只打印出准备好的语句,而不是完整的查询.我想看看它发送给MySQL的是什么,而是打印出一个准备好的声明,包括?'s.有没有办法看到'完整'的查询?
一个User有一个Package与它相关联.许多用户可以参考相同的包.User没有Package定义就不存在.User应该拥有这种关系.关系是双向的,因此其中Package包含零个或多个用户.
这些要求导致了Doctrine 2中的ManyToOne关系User和OneToMany关系Package.但是package_id在user表(即外键)中允许null值.我试过设置nullable=false但命令:
php app/console doctrine:generate:entities DL --path="src" --no-backup
Run Code Online (Sandbox Code Playgroud)
说这种nullable关系没有属性ManyToOne.我错过了什么?
class User
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Package", inversedBy="users")
*/
private $package;
}
class Package
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\OneToMany(targetEntity="User", …Run Code Online (Sandbox Code Playgroud) 我需要按两列排序数据(当行具有不同的列号1的值时,按顺序排序;否则,按列号2排序)
我正在使用a QueryBuilder来创建查询.
如果我orderBy第二次调用该方法,它将替换之前指定的任何排序.
我可以传递两列作为第一个参数:
->orderBy('r.firstColumn, r.secondColumn', 'DESC');
Run Code Online (Sandbox Code Playgroud)
但我无法为第二个参数传递两个排序方向,因此当我执行此查询时,第一列按升序排序,第二列按降序排序.我想对他们两个使用降序.
有没有办法使用QueryBuilder?我需要使用DQL吗?
我想使用Doctrine 2执行原始SQL
我需要截断数据库表并使用默认测试数据初始化表.
我的实体使用此注释作为其ID:
/**
* @orm:Id
* @orm:Column(type="integer")
* @orm:GeneratedValue(strategy="AUTO")
*/
protected $id;
Run Code Online (Sandbox Code Playgroud)
在干净的数据库中,我从旧数据库导入现有记录并尝试保留相同的ID.然后,在添加新记录时,我希望MySQL像往常一样自动增加ID列.
不幸的是,Doctrine2似乎完全忽略了指定的ID.
新解决方案
根据以下建议,以下是首选解决方案:
$this->em->persist($entity);
$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
Run Code Online (Sandbox Code Playgroud)
旧解决方案
因为Doctrine偏离ClassMetaData来确定生成器策略,所以在管理EntityManager中的实体之后必须对其进行修改:
$this->em->persist($entity);
$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$this->em->flush();
Run Code Online (Sandbox Code Playgroud)
我刚刚在MySQL上对它进行了测试,它按预期工作,这意味着具有自定义ID的实体与该ID一起存储,而没有指定ID的实体使用了lastGeneratedId() + 1.
我尝试收集有关以下方式的一些信息,以便在删除父实体时自动删除子实体.似乎最常见的方法是使用这三个注释:cascade = {"remove"} OR orphanRemoval = true OR ondelete ="CASCADE".
我对第三个问题感到有点困惑:ondelete ="CASCADE",正如关于这个的官方文档中的解释非常稀缺)如果有人能够证实我从我的研究中收集和了解的以下信息,我会很高兴.网和经验......
cascade = {"remove"}
==>当拥有方实体为时,删除反面的实体.即使你与其他拥有的实体有许多不同之处.
- 应该用于集合(所以在OneToMany或ManyToMany关系中)
- 在ORM中实现
orphanRemoval = true
==>当拥有方实体为AND时,将删除反方的实体,并且它不再连接到任何其他拥有方实体.(参考 doctrine official_doc
- ORM中的实现
- 可以与OneToOne,OnetoMany或ManyToMany一起使用
onDelete ="CASCADE"
==>这会将删除级联添加到数据库中的外键列
- 这个策略有点难以实现,但可以非常强大和快速.(参见 doctrine official_doc ......但还没有阅读更多解释)
- ORM必须做的工作少(与之前的两种做法相比),因此应该有更好的表现.
其他信息
- 所有这三种方式都在双向关系实体实现(右???)
- 使用cascade = {"remove"}完全绕过任何外键onDelete = CASCADE.(参见doctrine_official_doc)
级联= { "去除"}
/**
* @OneToMany(targetEntity="Phonenumber", mappedBy="contact", …Run Code Online (Sandbox Code Playgroud) 我正在开发游戏应用程序并使用Symfony 2.0.我对后端有很多AJAX请求.更多的响应是将实体转换为JSON.例如:
class DefaultController extends Controller
{
public function launchAction()
{
$user = $this->getDoctrine()
->getRepository('UserBundle:User')
->find($id);
// encode user to json format
$userDataAsJson = $this->encodeUserDataToJson($user);
return array(
'userDataAsJson' => $userDataAsJson
);
}
private function encodeUserDataToJson(User $user)
{
$userData = array(
'id' => $user->getId(),
'profile' => array(
'nickname' => $user->getProfile()->getNickname()
)
);
$jsonEncoder = new JsonEncoder();
return $jsonEncoder->encode($userData, $format = 'json');
}
}
Run Code Online (Sandbox Code Playgroud)
我的所有控制器都做同样的事情:获取一个实体并将其一些字段编码为JSON.我知道我可以使用规范化器并对所有权限进行编码.但是,如果一个实体已经循环链接到其他实体呢?或实体图非常大?你有什么建议吗?
我想一下实体的一些编码模式......或者NormalizableInterface用来避免循环..,