SonataDoctrineORMAdminBundle: Admin creates too many queries

Following https://github.com/sonata-project/SonataAdminBundle/issues/3924

Question Answer
Bundle version composer show sonata-project/*
sonata-project/admin-bundle 3.x-dev 62c313c The missing Symfony Admin Generator
sonata-project/block-bundle 3.x-dev ee778ac Symfony SonataBlockBundle
sonata-project/cache 1.0.7 Cache library
sonata-project/classification-bundle 3.x-dev aa61d55 Symfony SonataClassificationBundle
sonata-project/core-bundle 3.x-dev d2f84a6 Symfony SonataCoreBundle
sonata-project/datagrid-bundle dev-master 311afa1 Symfony SonataDatagridBundle
sonata-project/doctrine-extensions 1.0.2 Doctrine2 behavioral extensions
sonata-project/doctrine-orm-admin-bundle 3.x-dev 3c85820 Symfony Sonata / Integrate Doctrine ORM into the SonataAdminBundle
sonata-project/easy-extends-bundle 2.1.10 Symfony SonataEasyExtendsBundle
sonata-project/exporter 1.4.1 Lightweight Exporter library
sonata-project/intl-bundle 2.2.4 Symfony SonataIntlBundle
sonata-project/media-bundle 3.x-dev ec413fa Symfony SonataMediaBundle
sonata-project/notification-bundle 3.0.0 Symfony SonataNotificationBundle
Symfony version composer show symfony/*
symfony/assetic-bundle v2.8.0 Integrates Assetic into Symfony2
symfony/monolog-bundle 2.11.1 Symfony MonologBundle
symfony/polyfill-apcu v1.2.0 Symfony polyfill backporting apcu_* functions to lower PHP versions
symfony/polyfill-intl-icu v1.2.0 Symfony polyfill for intl’s ICU-related data and classes
symfony/polyfill-mbstring v1.2.0 Symfony polyfill for the Mbstring extension
symfony/polyfill-php54 v1.2.0 Symfony polyfill backporting some PHP 5.4+ features to lower PHP versions
symfony/polyfill-php55 v1.2.0 Symfony polyfill backporting some PHP 5.5+ features to lower PHP versions
symfony/polyfill-php56 v1.2.0 Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions
symfony/polyfill-php70 v1.2.0 Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions
symfony/polyfill-util v1.2.0 Symfony utilities for portability of PHP codes
symfony/security-acl v3.0.0 Symfony Security Component - ACL (Access Control List)
symfony/swiftmailer-bundle v2.3.11 Symfony SwiftmailerBundle
symfony/symfony v2.8.6 The Symfony PHP framework
php version php --version
PHP 5.6.20 (cli) (built: Mar 31 2016 14:56:44)
Copyright © 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright © 1998-2016 Zend Technologies

Error message

The SF debug bar shows too many queries on all my admin classes. My admin classes have nothing custom. I played a bit with my entities and found out that if I delete the mappedBy fields from my User class, it doesn’t do those queries anymore, but then the entity is not valid anymore, since it needs mappedBy for every inversedBy field.

Steps to reproduce

The admin’s entity

/**
 * @ORM\Table()
 * @ORM\Entity
 */
class BannedUsers
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(referencedColumnName="id",onDelete="CASCADE")
     */
    private $user;

    /**
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(referencedColumnName="id",onDelete="CASCADE")
     */
    private $censor;

    /**
     * @ORM\Column(type="string",nullable=true,length=2000)
     */
    private $reason;


    /**
     * @ORM\Column(type="boolean")
     */
    private $isBanActive=true;

    /**
     * @ORM\Column(type="datetime")
     * @Timestampable(on="create")
     */
    private $bannedAt;

This is my user class, pretty big but maybe it helps:

/**
 * @ORM\Entity(repositoryClass="UserRepository")
 * @ORM\Table(name="fos_user")
 */
class User extends BaseUser
{
    const DEFAULT_PATIENT_CREDIT = 300;

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="MedAppBundle\Entity\Group",inversedBy="users")
     * @ORM\JoinTable(name="fos_user_user_group",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id",onDelete="CASCADE")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
     * )
     */
    protected $groups;


    /**
     * @var string
     * @Assert\NotBlank(message="user.firstname.blank",groups={"Profile"})
     * @ORM\Column(name="firstname", type="string",nullable=true)
     */
    protected $firstname;

    /**
     * @var string
     * @Assert\NotBlank(message="user.lastname.blank",groups={"Profile"})
     * @ORM\Column(name="lastname", type="string",nullable=true)
     */
    protected $lastname;

    /**
     * @var string
     *
     * @ORM\Column(name="phoneno", type="string",nullable=true)
     */
    protected $phoneno;

    /**
     * @var string
     *
     * @ORM\Column(name="registration_ip", type="string",nullable=true)
     */
    protected $registrationIp;

    /**
     * @var string
     *
     * @ORM\Column(name="effects", type="boolean")
     */
    protected $effects = true;
    /**
     *
     * @ORM\Column(name="public_email", type="boolean")
     */
    protected $public_email = true;
    /**
     * @Assert\Valid
     * @ORM\OneToOne(targetEntity="MedAppBundle\Entity\MedicSettings",mappedBy="medic", cascade={"persist"})
     * @Assert\Valid()
     */
    protected $medicinfo;
    /**
     * @ORM\OneToMany(targetEntity="MedAppBundle\Entity\MedicComm",mappedBy="medic")
     */
    protected $mediccomm;

    /**
     * @ORM\OneToOne(targetEntity="PrivateMessageBundle\Entity\MessageSettings",mappedBy="user",cascade={"persist"})
     */
    protected $messageSettings;


    /**
     * @ORM\OneToOne(targetEntity="SupportMessageBundle\Entity\TicketSettings",mappedBy="user",cascade={"persist"})
     */
    protected $ticketSettings;

    /**
     * @ORM\OneToOne(targetEntity="Application\Sonata\MediaBundle\Entity\Media",cascade={"persist"})
     * @ORM\JoinColumn(referencedColumnName="id",onDelete="SET NULL")
     */
    protected $profilepic;

    /**
     * @var Media
     *
     * @ORM\OneToMany(targetEntity="Application\Sonata\MediaBundle\Entity\Media", mappedBy="user")
     * @ORM\JoinColumn(name="images", referencedColumnName="id",nullable=true)
     */
    private $images;

    /**
     * @var Media
     *
     * @ORM\OneToMany(targetEntity="Application\Sonata\MediaBundle\Entity\Gallery", mappedBy="user")
     * @ORM\JoinColumn(name="galleries", referencedColumnName="id",nullable=true)
     */
    private $galleries;



    /**
     * @var float
     *
     * @ORM\Column(name="credit", type="float")
     */
    protected $credit = 0;

    /**
     *
     * @ORM\ManyToOne(targetEntity="MedAppBundle\Entity\User")
     * @ORM\JoinColumn(name="referredBy", referencedColumnName="id",nullable=true,onDelete="SET NULL")
     */
    protected $referredBy;

    /**
     * @var string
     *
     * @ORM\Column(name="locationData", type="string",nullable=true)
     */
    protected $locationData;

    /**
     * @ORM\OneToMany(targetEntity="MedAppBundle\Entity\Stream",mappedBy="streamer")
     * @ORM\JoinColumn(referencedColumnName="id")
     */
    private $streams;

    /**
     * @var string
     *
     * @ORM\Column(name="savedFilters", type="string",nullable=true)
     */
    protected $savedFilters;


    /**
     *
     * @ORM\Column(name="registration_date", type="datetime",nullable=true)
     */
    protected $registrationDate;

    /**
     * @ORM\OneToMany(targetEntity="MedAppBundle\Entity\FavoriteUsers",mappedBy="user")
     * @ORM\JoinColumn(referencedColumnName="id")
     */
    private $favUsers;

    /**
     * @var string
     *
     * @ORM\Column(name="chosen_theme", type="string",nullable=true)
     */
    protected $chosenTheme;

    /**
     * @var string
     *
     * @ORM\Column(name="site_lang", type="string",nullable=true)
     */
    protected $siteLang;

    /**
     * @var integer
     *
     * @ORM\Column(name="total_time_live", type="integer", nullable=true)
     *
     */
    protected $totalTimeLive;

    /**
     *
     * @ORM\ManyToOne(targetEntity="FirmBundle\Entity\Firm",inversedBy="firmAdmins", cascade={"persist"})
     */
    protected $adminOfFirm;

    /**
     * @ORM\OneToMany(targetEntity="MedAppBundle\Entity\EmailList",mappedBy="user")
     * @ORM\JoinColumn(referencedColumnName="id")
     */
    private $emailList;

    /**
     * @ORM\OneToOne(targetEntity="MedAppBundle\Entity\Newsletter",mappedBy="user")
     * @ORM\JoinColumn(referencedColumnName="id")
     */
    private $newsletter;

    /**
     * @var string
     *
     * @ORM\Column(name="folderName", type="string", nullable=true)
     */
    public $folderName;

    /**
     *
     * @ORM\Column(name="bonus_received", type="boolean")
     */
    protected $bonusReceived = false;

    /**
     *
     * @ORM\Column(name="purchase_bonus_eligibility", type="boolean", options={"default" = true }, nullable=true )
     */
    protected $purchaseBonusEligibility;

    /**
     * @ORM\OneToMany(targetEntity="MedAppBundle\Entity\PendingProfileImage",mappedBy="user")
     */
    protected $pendingProfileImages;

    /**
     * @ORM\Column(name="is_validated_phone_no", type="boolean", nullable=true)
     */
    private $isValidatedPhoneNo;

    /**
     * @ORM\Column(name="mobile_validation_pin", type="string", nullable=true)
     */
    private $mobileValidationPin;

    /**
     * @ORM\Column(name="username_token", type="string", nullable=true, options={"default" = true })
     */
    private $usernameToken;




    /**
     * @ORM\OneToOne(targetEntity="MedAppBundle\Entity\AccountDocument", mappedBy="user")
     */
    private $accountDocument;


    /**
     * @ORM\OneToMany(targetEntity="MedAppBundle\Entity\AccountDocument", mappedBy="takenByAdmin")
     * @ORM\JoinColumn(referencedColumnName="id",onDelete="CASCADE")
     */
    private $takenPending;

Expected results

If I delete all the mappedBy fields, the same page on my admin shows less queries, as I want it to be, but invalid entity:

image

Here’s the queries table https://jsfiddle.net/nmxz4j7y/

Actual results

Here’s one of my admin classes’s example:

image

Here’s the query table: https://jsfiddle.net/nmxz4j7y/1/

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 55 (25 by maintainers)

Most upvoted comments

Done. The query is the last one in the query list:

        $query
            ->addSelect('user')
            ->leftJoin($query->getRootAlias().'.user', 'user')
            ->leftJoin($query->getRootAlias().'.censor', 'censor')
            ->orderBy('user.username','ASC');
        ;


        return $query;
SELECT b0_.id AS id_0, b0_.reason AS reason_1, b0_.is_ban_active AS is_ban_active_2, b0_.banned_at AS banned_at_3, f1_.username AS username_4, f1_.username_canonical AS username_canonical_5, f1_.email AS email_6, f1_.email_canonical AS email_canonical_7, f1_.enabled AS enabled_8, f1_.salt AS salt_9, f1_.password AS password_10, f1_.last_login AS last_login_11, f1_.locked AS locked_12, f1_.expired AS expired_13, f1_.expires_at AS expires_at_14, f1_.confirmation_token AS confirmation_token_15, f1_.password_requested_at AS password_requested_at_16, f1_.roles AS roles_17, f1_.credentials_expired AS credentials_expired_18, f1_.credentials_expire_at AS credentials_expire_at_19, f1_.id AS id_20, f1_.firstname AS firstname_21, f1_.lastname AS lastname_22, f1_.phoneno AS phoneno_23, f1_.registration_ip AS registration_ip_24, f1_.effects AS effects_25, f1_.public_email AS public_email_26, f1_.credit AS credit_27, f1_.locationData AS locationData_28, f1_.savedFilters AS savedFilters_29, f1_.registration_date AS registration_date_30, f1_.chosen_theme AS chosen_theme_31, f1_.site_lang AS site_lang_32, f1_.total_time_live AS total_time_live_33, f1_.folderName AS folderName_34, f1_.bonus_received AS bonus_received_35, f1_.purchase_bonus_eligibility AS purchase_bonus_eligibility_36, f1_.is_validated_phone_no AS is_validated_phone_no_37, f1_.mobile_validation_pin AS mobile_validation_pin_38, f1_.username_token AS username_token_39, b0_.user_id AS user_id_40, b0_.censor_id AS censor_id_41, f1_.profilepic_id AS profilepic_id_42, f1_.referredBy AS referredBy_43, f1_.admin_of_firm_id AS admin_of_firm_id_44, f1_.newsletter_id AS newsletter_id_45 FROM banned_users b0_ LEFT JOIN fos_user f1_ ON b0_.user_id = f1_.id LEFT JOIN fos_user f2_ ON b0_.censor_id = f2_.id WHERE b0_.id IN (?) ORDER BY f1_.username ASC, b0_.id DESC
Parameters: [[2]]
Hide formatted query    Hide runnable query    Hide query explanation
SELECT 
  b0_.id AS id_0, 
  b0_.reason AS reason_1, 
  b0_.is_ban_active AS is_ban_active_2, 
  b0_.banned_at AS banned_at_3, 
  f1_.username AS username_4, 
  f1_.username_canonical AS username_canonical_5, 
  f1_.email AS email_6, 
  f1_.email_canonical AS email_canonical_7, 
  f1_.enabled AS enabled_8, 
  f1_.salt AS salt_9, 
  f1_.password AS password_10, 
  f1_.last_login AS last_login_11, 
  f1_.locked AS locked_12, 
  f1_.expired AS expired_13, 
  f1_.expires_at AS expires_at_14, 
  f1_.confirmation_token AS confirmation_token_15, 
  f1_.password_requested_at AS password_requested_at_16, 
  f1_.roles AS roles_17, 
  f1_.credentials_expired AS credentials_expired_18, 
  f1_.credentials_expire_at AS credentials_expire_at_19, 
  f1_.id AS id_20, 
  f1_.firstname AS firstname_21, 
  f1_.lastname AS lastname_22, 
  f1_.phoneno AS phoneno_23, 
  f1_.registration_ip AS registration_ip_24, 
  f1_.effects AS effects_25, 
  f1_.public_email AS public_email_26, 
  f1_.credit AS credit_27, 
  f1_.locationData AS locationData_28, 
  f1_.savedFilters AS savedFilters_29, 
  f1_.registration_date AS registration_date_30, 
  f1_.chosen_theme AS chosen_theme_31, 
  f1_.site_lang AS site_lang_32, 
  f1_.total_time_live AS total_time_live_33, 
  f1_.folderName AS folderName_34, 
  f1_.bonus_received AS bonus_received_35, 
  f1_.purchase_bonus_eligibility AS purchase_bonus_eligibility_36, 
  f1_.is_validated_phone_no AS is_validated_phone_no_37, 
  f1_.mobile_validation_pin AS mobile_validation_pin_38, 
  f1_.username_token AS username_token_39, 
  b0_.user_id AS user_id_40, 
  b0_.censor_id AS censor_id_41, 
  f1_.profilepic_id AS profilepic_id_42, 
  f1_.referredBy AS referredBy_43, 
  f1_.admin_of_firm_id AS admin_of_firm_id_44, 
  f1_.newsletter_id AS newsletter_id_45 
FROM 
  banned_users b0_ 
  LEFT JOIN fos_user f1_ ON b0_.user_id = f1_.id 
  LEFT JOIN fos_user f2_ ON b0_.censor_id = f2_.id 
WHERE 
  b0_.id IN (?) 
ORDER BY 
  f1_.username ASC, 
  b0_.id DESC
SELECT b0_.id AS id_0, b0_.reason AS reason_1, b0_.is_ban_active AS is_ban_active_2, b0_.banned_at AS banned_at_3, f1_.username AS username_4, f1_.username_canonical AS username_canonical_5, f1_.email AS email_6, f1_.email_canonical AS email_canonical_7, f1_.enabled AS enabled_8, f1_.salt AS salt_9, f1_.password AS password_10, f1_.last_login AS last_login_11, f1_.locked AS locked_12, f1_.expired AS expired_13, f1_.expires_at AS expires_at_14, f1_.confirmation_token AS confirmation_token_15, f1_.password_requested_at AS password_requested_at_16, f1_.roles AS roles_17, f1_.credentials_expired AS credentials_expired_18, f1_.credentials_expire_at AS credentials_expire_at_19, f1_.id AS id_20, f1_.firstname AS firstname_21, f1_.lastname AS lastname_22, f1_.phoneno AS phoneno_23, f1_.registration_ip AS registration_ip_24, f1_.effects AS effects_25, f1_.public_email AS public_email_26, f1_.credit AS credit_27, f1_.locationData AS locationData_28, f1_.savedFilters AS savedFilters_29, f1_.registration_date AS registration_date_30, f1_.chosen_theme AS chosen_theme_31, f1_.site_lang AS site_lang_32, f1_.total_time_live AS total_time_live_33, f1_.folderName AS folderName_34, f1_.bonus_received AS bonus_received_35, f1_.purchase_bonus_eligibility AS purchase_bonus_eligibility_36, f1_.is_validated_phone_no AS is_validated_phone_no_37, f1_.mobile_validation_pin AS mobile_validation_pin_38, f1_.username_token AS username_token_39, b0_.user_id AS user_id_40, b0_.censor_id AS censor_id_41, f1_.profilepic_id AS profilepic_id_42, f1_.referredBy AS referredBy_43, f1_.admin_of_firm_id AS admin_of_firm_id_44, f1_.newsletter_id AS newsletter_id_45 FROM banned_users b0_ LEFT JOIN fos_user f1_ ON b0_.user_id = f1_.id LEFT JOIN fos_user f2_ ON b0_.censor_id = f2_.id WHERE b0_.id IN (2) ORDER BY f1_.username ASC, b0_.id DESC;

Maybe upgrade Composer?

I have a small problem, I tried doing something like

    public function createQuery($context = 'list')
    {
        $query = parent::createQuery($context);

        $query
            ->addSelect('User')
            ->leftJoin($query->getRootAlias().'.user', 'user')
        ;

        return $query;
    }

because I thought to do it as a temporary solution, but this doesn’t change anything. I’m getting the same queries, and this query doesn’t even appear in the list. I think it might be because of the aliases. While here I am aliasing with user, the actual alias used in the query is t0 as seen above, and the root alias is always o

So not even this works.

The query resulted from the parent is

SELECT o FROM MedAppBundle\Entity\BannedUsers o

And after my join:

SELECT o, user FROM MedAppBundle\Entity\BannedUsers o LEFT JOIN o.user user

But it’s never used, I don’t see it in the query list in the debug toolbar.