Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unknown column 'ClassName' in 'field list' #10737

Closed
MauritzFunke opened this issue Mar 27, 2023 · 11 comments
Closed

Unknown column 'ClassName' in 'field list' #10737

MauritzFunke opened this issue Mar 27, 2023 · 11 comments

Comments

@MauritzFunke
Copy link

MauritzFunke commented Mar 27, 2023

Affected Version

4.11.0

Description

ClassName not found

Steps to Reproduce

I created the following DataObject

<?php

use gorriecoe\Link\Models\Link;
use gorriecoe\LinkField\LinkField;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataObject;

class Information extends DataObject {
    private static $singular_name = "Information";
    private static $plural_name = "Informationen";

    private static $db = [
        'Name' => 'Text'
    ];
    private static $has_one = [
        "Page" => Page::class
    ];

    private static $many_many = [
        'Links' => Link::class
    ];
    
    private static $many_many_extraFields = [
        'Links' => [
            'Sort' => 'Int'
        ]
    ];

    public function getCMSFields()
    {
        $fields = parent::getCMSFields();
        $fields->addFieldToTab(
            "Root.Main",
            TextField::create('Name', 'Name')
        );
        $fields->addFieldToTab(
            "Root.Main",
            LinkField::create('Links', 'Links', $this)
        );
        return $fields;
    }
}

and make a /dev/build

And now, every time I want to add a link I get the following error

[Emergency] Uncaught SilverStripe\ORM\Connect\DatabaseException: Couldn't run query: SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1 Unknown column 'Information.ClassName' in 'field list'
GET /admin/pages/edit/EditForm/20/field/Informations/item/1/ItemEditForm/field/Links/item/new

Line 64 in /vendor/silverstripe/framework/src/ORM/Connect/DBConnector.php
Source

55         if (!empty($sql)) {
56             $formatter = new SQLFormatter();
57             $formattedSQL = $formatter->formatPlain($sql);
58             $msg = "Couldn't run query:\n\n{$formattedSQL}\n\n{$msg}";
59         }
60 
61         if ($errorLevel === E_USER_ERROR) {
62             // Treating errors as exceptions better allows for responding to errors
63             // in code, such as credential checking during installation
64             throw new DatabaseException($msg, 0, null, $sql, $parameters);
65         } else {
66             user_error($msg ?? '', $errorLevel ?? 0);
67         }
68     }
69 
70     /**

Trace

    SilverStripe\ORM\Connect\DBConnector->databaseError(Couldn't run query: SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1 Unknown column 'Information.ClassName' in 'field list', 256, SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1, Array)
    MySQLiConnector.php:306
    SilverStripe\ORM\Connect\MySQLiConnector->preparedQuery(SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1, Array, 256)
    Database.php:185
    SilverStripe\ORM\Connect\Database->SilverStripe\ORM\Connect\{closure}(SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1)
    Database.php:258
    SilverStripe\ORM\Connect\Database->benchmarkQuery(SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1, Closure, Array)
    Database.php:183
    SilverStripe\ORM\Connect\Database->preparedQuery(SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1, Array, 256)
    MySQLDatabase.php:402
    SilverStripe\ORM\Connect\MySQLDatabase->preparedQuery(SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1, Array, 256)
    DB.php:445
    SilverStripe\ORM\DB::prepared_query(SELECT DISTINCT CASE WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort" WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" ELSE NULL END AS "Sort", "Link"."ClassName", "Link"."LastEdited", "Link"."Created", "Link"."Anchor", "Link"."Title", "Link"."Type", "Link"."URL", "Link"."Email", "Link"."Phone", "Link"."OpenInNewWindow", "Link"."SelectedStyle", "Link"."SiteTreeID", "Link"."FileID", "Link"."ID", CASE WHEN "Link"."ClassName" IS NOT NULL THEN "Link"."ClassName" ELSE 'gorriecoe\\Link\\Models\\Link' END AS "RecordClassName" FROM "Link" INNER JOIN "Information_Links" ON "Information_Links"."LinkID" = "Link"."ID" WHERE ("Information_Links"."InformationID" = ?) AND ("Link"."ID" = ?) LIMIT 1, Array)
    SQLExpression.php:115
    SilverStripe\ORM\Queries\SQLExpression->execute()
    DataList.php:940
    SilverStripe\ORM\DataList->first()
    DataList.php:1019
    SilverStripe\ORM\DataList->byID(0)
    GridFieldLinkDetailForm.php:45
    gorriecoe\LinkField\Forms\GridField\GridFieldLinkDetailForm->getRecordFromRequest(SilverStripe\Forms\GridField\GridField, SilverStripe\Control\HTTPRequest)
    GridFieldDetailForm.php:123
    SilverStripe\Forms\GridField\GridFieldDetailForm->handleItem(SilverStripe\Forms\GridField\GridField, SilverStripe\Control\HTTPRequest)
    GridField.php:1182
    SilverStripe\Forms\GridField\GridField->handleRequest(SilverStripe\Control\HTTPRequest)
    LinkField.php:141
    gorriecoe\LinkField\LinkField->handleRequest(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:226
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:226
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    GridFieldDetailForm.php:149
    SilverStripe\Forms\GridField\GridFieldDetailForm->handleItem(SilverStripe\Forms\GridField\GridField, SilverStripe\Control\HTTPRequest)
    GridField.php:1182
    SilverStripe\Forms\GridField\GridField->handleRequest(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:226
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:226
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    Controller.php:212
    SilverStripe\Control\Controller->handleRequest(SilverStripe\Control\HTTPRequest)
    LeftAndMain.php:779
    SilverStripe\Admin\LeftAndMain->handleRequest(SilverStripe\Control\HTTPRequest)
    AdminRootController.php:123
    SilverStripe\Admin\AdminRootController->handleRequest(SilverStripe\Control\HTTPRequest)
    Director.php:360
    SilverStripe\Control\Director->SilverStripe\Control\{closure}(SilverStripe\Control\HTTPRequest)
    VersionedHTTPMiddleware.php:41
    SilverStripe\Versioned\VersionedHTTPMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    LoginSessionMiddleware.php:53
    SilverStripe\SessionManager\Middleware\LoginSessionMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    ExecMetricMiddleware.php:20
    SilverStripe\Control\Middleware\ExecMetricMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    ConfirmationMiddleware.php:254
    SilverStripe\Control\Middleware\ConfirmationMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    ConfirmationMiddleware.php:254
    SilverStripe\Control\Middleware\ConfirmationMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    PasswordExpirationMiddleware.php:84
    SilverStripe\Security\PasswordExpirationMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    BasicAuthMiddleware.php:68
    SilverStripe\Security\BasicAuthMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    AuthenticationMiddleware.php:61
    SilverStripe\Security\AuthenticationMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    CanonicalURLMiddleware.php:190
    SilverStripe\Control\Middleware\CanonicalURLMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    HTTPCacheControlMiddleware.php:42
    SilverStripe\Control\Middleware\HTTPCacheControlMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    ChangeDetectionMiddleware.php:28
    SilverStripe\Control\Middleware\ChangeDetectionMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    FlushMiddleware.php:27
    SilverStripe\Control\Middleware\FlushMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    RequestProcessor.php:66
    SilverStripe\Control\RequestProcessor->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    SessionMiddleware.php:20
    SilverStripe\Control\Middleware\SessionMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    AllowedHostsMiddleware.php:60
    SilverStripe\Control\Middleware\AllowedHostsMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    TrustedProxyMiddleware.php:176
    SilverStripe\Control\Middleware\TrustedProxyMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    HTTPMiddlewareAware.php:65
    SilverStripe\Control\Director->callMiddleware(SilverStripe\Control\HTTPRequest, Closure)
    Director.php:369
    SilverStripe\Control\Director->handleRequest(SilverStripe\Control\HTTPRequest)
    HTTPApplication.php:117
    SilverStripe\Control\HTTPApplication::SilverStripe\Control\{closure}(SilverStripe\Control\HTTPRequest)
    call_user_func(Closure, SilverStripe\Control\HTTPRequest)
    HTTPApplication.php:136
    SilverStripe\Control\HTTPApplication->SilverStripe\Control\{closure}(SilverStripe\Control\HTTPRequest)
    HTTPMiddlewareAware.php:65
    SilverStripe\Control\HTTPApplication->callMiddleware(SilverStripe\Control\HTTPRequest, Closure)
    HTTPApplication.php:137
    SilverStripe\Control\HTTPApplication->execute(SilverStripe\Control\HTTPRequest, Closure, )
    HTTPApplication.php:116
    SilverStripe\Control\HTTPApplication->handle(SilverStripe\Control\HTTPRequest)
    index.php:24

@michalkleiner
Copy link
Contributor

I don't think you can use LinkField to manage a many_many relationship this way. It's a field to add a single link, so requires a has_one relationship. This is not an issue of the framework.

@michalkleiner
Copy link
Contributor

Hmm, actually looking at the docs for the module, it looks like it supports many_many. So someone would need to figure out whether it's an issue with the module or with the framework.

@michalkleiner michalkleiner reopened this Mar 27, 2023
@NightJar
Copy link
Contributor

NightJar commented Mar 28, 2023

Information extends DataObject.
DataObject always has ClassName field on it.

It is an odd error.

By the query SELECT it looks as though the model might have previously extend Link rather than DataObject, and a dev/build hasn't taken place to correct the table structure yet.

CASE 
  WHEN "Information"."ClassName" IN ('Information') THEN "Information_Links"."Sort"
  WHEN "Link"."ClassName" IN ('gorriecoe\\Link\\Models\\Link') THEN "Link"."Sort" 
  ELSE NULL
END AS "Sort"

Has an error happened while you try to perform a dev/build @MauritzFunke

@MauritzFunke
Copy link
Author

No. Also, I didn't extend Link. I only used to extend DataObject. One thing I want to add is that ClassName is a column in Information.
I edited the DataObject structure a bit to test so maybe there are columns that are not needed with my exact dataobject.

I would also want to add that if I only use has_one everything works fine.

My create table:

CREATE TABLE `Information` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `ClassName` enum('Information') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 'Information',
  `LastEdited` datetime DEFAULT NULL,
  `Created` datetime DEFAULT NULL,
  `Title` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `LinksID` int(11) NOT NULL DEFAULT 0,
  `Name` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `PageID` int(11) NOT NULL DEFAULT 0,
  PRIMARY KEY (`ID`),
  KEY `ClassName` (`ClassName`),
  KEY `LinksID` (`LinksID`),
  KEY `PageID` (`PageID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 COLLATE=latin1_german1_ci

@michalkleiner
Copy link
Contributor

@MauritzFunke can you please confirm this — is this an issue when you start a fresh project using the installer instructions and just add your dataobject as specified in the issue description and run dev/build?flush? Or did you take any other steps before or after starting fresh?

@MauritzFunke
Copy link
Author

This was not a fresh project. It is a longer project I'm working on. Will check if error persists on a fresh project

@NightJar
Copy link
Contributor

NightJar commented Mar 29, 2023

These fields should exist on every DataObject:

private static $fixed_fields = [
'ID' => 'PrimaryKey',
'ClassName' => 'DBClassName',
'LastEdited' => 'DBDatetime',
'Created' => 'DBDatetime',
];

This is why the error is so confusing and needs more information to debug :)

I suppose this is configurable... if the project were to override or add to this fixed_fields config, that might cause problems. But normally config is merged, rather than overridden. Explicitly unsetting this would surely break more areas in the framework than just this DataObject.

@tiller1010
Copy link
Contributor

I am experiencing the same issue. It only occurs when there are many_many_extraFields. The final query seems to be missing the join clause for the OfficeBranch class:

class Doctor extends DataObject
{
  private static $belongs_many_many = [
    'AdditionalOfficeBranches' => OfficeBranch::class . '.AdditionalDoctors',
  ];
}
class OfficeBranch extends DataObject
{
  private static $many_many = [
    'AdditionalDoctors' => Doctor::class,
  ];

  private static $many_many_extraFields = [
    'AdditionalDoctors' => [
      'Suite' => 'Varchar',
      'Phone' => 'Varchar',
      'Fax' => 'Varchar',
      'SortOrder' => 'Int',
    ],
  ];
}

Without the many_many_extraFields, $officeBranch->AdditionalDoctors()->toArray() does not error, and it produces the following query:

"SELECT DISTINCT "OfficeBranch_Live"."ClassName", "OfficeBranch_Live"."LastEdited", "OfficeBranch_Live"."Created", "OfficeBranch_Live"."Version", "OfficeBranch_Live"."Title", "OfficeBranch_Live"."AddressOne", "OfficeBranch_Live"."AddressTwo", "OfficeBranch_Live"."City", "OfficeBranch_Live"."State", "OfficeBranch_Live"."Zip", "OfficeBranch_Live"."Phone", "OfficeBranch_Live"."Fax", "OfficeBranch_Live"."Latitude", "OfficeBranch_Live"."Longitude", "OfficeBranch_Live"."SortOrder", "OfficeBranch_Live"."ExternalLink", "OfficeBranch_Live"."OfficeID", "OfficeBranch_Live"."LocationID", "OfficeBranch_Live"."InternalLinkID", "OfficeBranch_Live"."ID", CASE WHEN "OfficeBranch_Live"."ClassName" IS NOT NULL THEN "OfficeBranch_Live"."ClassName" ELSE 'OfficeBranch' END AS "RecordClassName" FROM "OfficeBranch_Live" INNER JOIN "OfficeBranch_AdditionalDoctors" ON "OfficeBranch_AdditionalDoctors"."OfficeBranchID" = "OfficeBranch_Live"."ID" WHERE ("OfficeBranch_AdditionalDoctors"."DoctorID" = ?) ORDER BY "OfficeBranch_Live"."SortOrder" ASC"

If many_many_extraFields are present, however, $officeBranch->AdditionalDoctors()->toArray() produces a query that is missing the INNER JOIN "OfficeBranch" ON "OfficeBranch_AdditionalDoctors"."OfficeBranchID" = "OfficeBranch"."ID" clause:

[Emergency] Uncaught SilverStripe\ORM\Connect\DatabaseException: Couldn't run query: SELECT DISTINCT "OfficeBranch_AdditionalDoctors"."Suite", CASE WHEN "OfficeBranch"."ClassName" IN ('OfficeBranch') THEN "OfficeBranch_AdditionalDoctors"."Phone" WHEN "Doctor"."ClassName" IN ('Doctor') THEN "Doctor"."Phone" ELSE NULL END AS "Phone", CASE WHEN "OfficeBranch"."ClassName" IN ('OfficeBranch') THEN "OfficeBranch_AdditionalDoctors"."Fax" WHEN "Doctor"."ClassName" IN ('Doctor') THEN "Doctor"."Fax" ELSE NULL END AS "Fax", "Doctor"."ClassName", "Doctor"."LastEdited", "Doctor"."Created", "Doctor"."Version", "Doctor"."FirstName", "Doctor"."LastName", "Doctor"."LinkText", "Doctor"."URLSegment", "Doctor"."SortOrder", "Doctor"."PhysicianInfo", "Doctor"."DoctorTitle", "Doctor"."Address", "Doctor"."OfficeBranchID", "Doctor"."ImageID", "Doctor"."ID", CASE WHEN "Doctor"."ClassName" IS NOT NULL THEN "Doctor"."ClassName" ELSE 'Doctor' END AS "RecordClassName" FROM "Doctor" INNER JOIN "OfficeBranch_AdditionalDoctors" ON "OfficeBranch_AdditionalDoctors"."DoctorID" = "Doctor"."ID" [ JOIN ON OFFICEBRANCH SHOULD GO HERE] WHERE ("OfficeBranch_AdditionalDoctors"."OfficeBranchID" = ?) ORDER BY "Doctor"."SortOrder" ASC Unknown column 'OfficeBranch.ClassName' in 'field list'

A temporary solution I have found is to simply define a new function and apply the join yourself:

$officeBranch->AdditionalDoctors()->innerJoin('OfficeBranch', 'OfficeBranch_AdditionalDoctors.OfficeBranchID = OfficeBranch.ID'),

@lekoala
Copy link
Contributor

lekoala commented Feb 7, 2024

@michalkleiner i can confirm the issue as well, just stumbled upon it while upgrading a project for ss3 to ss5. it was working fine before. as @tiller1010 said, it's indeed when there is a many_many_extraFields, the last inner join is missing and therefore the [ManyMany].ClassName field is not found

@lekoala
Copy link
Contributor

lekoala commented Feb 7, 2024

to be more precise, it seems the two classes need to share a common has_one or field name, like "Sort" in the OP ticket (or Member in mine)

lekoala added a commit to lekoala/silverstripe-framework that referenced this issue Feb 7, 2024
@GuySartorelli
Copy link
Member

PR merged. This will be automatically tagged by GitHub actions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants