批量导入时,如何填写多对一关系字段?
When batch importing, how do I fill in the field of a ManyToOne relationship?
我正在尝试导入一批记录(账单),但我(与客户)存在多对一关系。
如何填写该关系的数据库列?
我在实体内部使用类似 fromArray
的函数,我在其中传递字段列表和一条记录的值(数据源是 CSV)。然后在该函数内,我只需将每个列值分配给相应的 属性。但是,属性 客户是一个对象,因此我需要传入一个我没有的对象。
我考虑过将实体管理器注入我的实体,但这被认为是一种糟糕的做法,所以我有点卡住了。
我也尝试添加一个额外的 属性 customerId
希望它能强制写入值,但它似乎坚持 属性 值之上的关系值。
这是我的代码:
class Bill
/**
* @var string
*
* @ORM\Column(name="docId", type="string", length=25, nullable=false)
* @ORM\Id
*/
private $id;
/**
* @var float|null
*
* @ORM\Column(name="amount", type="float", precision=10, scale=0, nullable=true)
*/
private $amount;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Customer", inversedBy="bills")
* @ORM\JoinColumn(name="customerId", referencedColumnName="customerId", nullable=false)
*/
private $customer;
public function getCustomer(): ?Customer
{
return $this->customer;
}
public function setCustomer( $customer): self
{
$this->customer = $customer;
return $this;
}
//this is where we import
public static function fromCSVRecord($header, $line)
{
$object = new self;
foreach($header as $key => $field){
try{
switch($field){
case 'customerId':
//get the customer here from EM but we don't have EM
$customer = $em->getRepository(Customer::class)->find($line[$key]);
$object->setCustomer($customer);
break;
default:
$object->$field = $line[$key];
break;
}
}catch(\Exception $e){
dd($line[$key]);
}
}
return $object;
}
}
我希望有一种简单的方法可以使用 ORM 导入记录值,而不必将实体管理器注入实体 class。
你的问题是你试图把这个责任推给错误的人class。你需要实体内部的实体管理器的巨大代码味道,你正确地感知,正在暗示你这是执行该操作的错误位置。
将其移至存储库。无论如何,这是一个更合乎逻辑的地方来处理这个问题,而且您已经有了可用的实体管理器。
class BillRepository extends ServiceEntityRepository
{
//..
public function addFromCSVRecord($header, $line) {
$em = $this->getEntityManager();
$bill = new Bill();
foreach ($header as $key => $field) {
try {
switch ($field) {
case 'customerId':
$customer = $em->getRepository(Customer::class)->find($line[$key]);
// alternatively, if you are certain of the incoming data and you do not want to hit the DB...
// $customer = $this->getEntityManager()->getReference(Customer:class, $line[$key]);
$bill->setCustomer($customer);
break;
default:
$bill->$field = $line[$key];
break;
}
} catch (\Exception $e) { dd($line[$key]); }
}
// return $object;
$em->persist($bill);
$em->flush();
}
}
我将保留在您的方法中找到的大部分逻辑,因为我不知道具体细节。尽管更改了 return
以实际保留数据,因此对 addFromCsvRecord()
的一次调用将在数据库中创建并保留您的新对象。
请注意,在我的回答中,我向您展示了如何使用 EntityManager::getReference()
为您的客户生成对象引用。如果您可以信任输入文件,这会稍微快一些,因为您不需要为该对象访问数据库。
我正在尝试导入一批记录(账单),但我(与客户)存在多对一关系。 如何填写该关系的数据库列?
我在实体内部使用类似 fromArray
的函数,我在其中传递字段列表和一条记录的值(数据源是 CSV)。然后在该函数内,我只需将每个列值分配给相应的 属性。但是,属性 客户是一个对象,因此我需要传入一个我没有的对象。
我考虑过将实体管理器注入我的实体,但这被认为是一种糟糕的做法,所以我有点卡住了。
我也尝试添加一个额外的 属性 customerId
希望它能强制写入值,但它似乎坚持 属性 值之上的关系值。
这是我的代码:
class Bill
/**
* @var string
*
* @ORM\Column(name="docId", type="string", length=25, nullable=false)
* @ORM\Id
*/
private $id;
/**
* @var float|null
*
* @ORM\Column(name="amount", type="float", precision=10, scale=0, nullable=true)
*/
private $amount;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Customer", inversedBy="bills")
* @ORM\JoinColumn(name="customerId", referencedColumnName="customerId", nullable=false)
*/
private $customer;
public function getCustomer(): ?Customer
{
return $this->customer;
}
public function setCustomer( $customer): self
{
$this->customer = $customer;
return $this;
}
//this is where we import
public static function fromCSVRecord($header, $line)
{
$object = new self;
foreach($header as $key => $field){
try{
switch($field){
case 'customerId':
//get the customer here from EM but we don't have EM
$customer = $em->getRepository(Customer::class)->find($line[$key]);
$object->setCustomer($customer);
break;
default:
$object->$field = $line[$key];
break;
}
}catch(\Exception $e){
dd($line[$key]);
}
}
return $object;
}
}
我希望有一种简单的方法可以使用 ORM 导入记录值,而不必将实体管理器注入实体 class。
你的问题是你试图把这个责任推给错误的人class。你需要实体内部的实体管理器的巨大代码味道,你正确地感知,正在暗示你这是执行该操作的错误位置。
将其移至存储库。无论如何,这是一个更合乎逻辑的地方来处理这个问题,而且您已经有了可用的实体管理器。
class BillRepository extends ServiceEntityRepository
{
//..
public function addFromCSVRecord($header, $line) {
$em = $this->getEntityManager();
$bill = new Bill();
foreach ($header as $key => $field) {
try {
switch ($field) {
case 'customerId':
$customer = $em->getRepository(Customer::class)->find($line[$key]);
// alternatively, if you are certain of the incoming data and you do not want to hit the DB...
// $customer = $this->getEntityManager()->getReference(Customer:class, $line[$key]);
$bill->setCustomer($customer);
break;
default:
$bill->$field = $line[$key];
break;
}
} catch (\Exception $e) { dd($line[$key]); }
}
// return $object;
$em->persist($bill);
$em->flush();
}
}
我将保留在您的方法中找到的大部分逻辑,因为我不知道具体细节。尽管更改了 return
以实际保留数据,因此对 addFromCsvRecord()
的一次调用将在数据库中创建并保留您的新对象。
请注意,在我的回答中,我向您展示了如何使用 EntityManager::getReference()
为您的客户生成对象引用。如果您可以信任输入文件,这会稍微快一些,因为您不需要为该对象访问数据库。