4

我正在使用 CakePHP 3.3.9 并尝试使用friendsofcake/search插件 + 分页来过滤AssessmentLogs基于的列表Clients.EmrSystems,其中EmrSystems是 on 的 belongsToMany 关联Clients。如果它有所作为,这一切都在 SQL Server 数据库上。

我的问题是,当我使用matching()并且contain()我收到正确的结果但记录Client中缺少关联时AssessmentLog,即使它被明确包含。我不关心在 each 下获得EmrSystemsfor a ,只关心拥有它的那个。ClientAssessmentLogClient

client生成的查询甚至看起来是正确的,但 ORM 对于每条记录的关联只有一个空值。甚至根据 DebugKit_matchingData包含,所以我知道那里有正确的信息。client手动运行生成的查询甚至会返回正确的结果。

以下是关联的布局方式:

评估日志表

// AssessmentLog belongs to a Client using ClientId field
$this->belongsTo('Clients', [
    'foreignKey' => 'ClientId'
]);

// Search plugin
$this->searchManager()->add('EmrSystem', 'Search.Callback', [
    'callback' => function ($query, $args, $manager) {
        if (!is_array($args['EmrSystem'])) {
            return false;
        }

        // Not returning the Client association for some reason :(
        // Should return only assessment logs where the client has a specified EMR system.
        // The AssessmentLog should always contain the Client association

        return $query->contain([
            'Clients',
            'Clients.EmrSystems'
        ])
        ->matching('Clients.EmrSystems', function ($q) use ($args) {
            return $q->where(function ($exp) use ($args) {
                return $exp->in('EmrSystems.ID', $args['EmrSystem']);
            });
        });
    },
    'filterEmpty' => true
]);

客户表

// Client has many assessment logs - The ID fields aren't named consistently and wasn't my choice or design. The field name is correct.
$this->hasMany('AssessmentLogs', [
    'foreignKey' => 'ClientID'
]);

// Client can have multiple EMR (Electronic Medical Record) systems
$this->belongsToMany('EmrSystems', [
    'joinTable' => 'ClientEmrSystem',
    'foreignKey' => 'ClientId',
    'targetForeignKey' => 'EmrSystemId',
    'through' => 'ClientEmrSystems',
    'saveStrategy' => 'replace'
]);

评估日志控制器

// Load other associations
$this->paginate['contain'] = [
    'AssessmentTypes' => function ($q) {
        return $q->select([
            'AssessmentTypes.AssessmentTypeCd',
            'AssessmentTypes.AssessmentTypeShort'
        ]);
    },
    'Clients' => function ($q) {
        return $q->select([
            'Clients.ClientId',
            'Clients.OrganizationName'
        ]);
    },
    'Patients' => function ($q) {
        return $q->select([
            'Patients.PatientId',
            'Patients.FirstName',
            'Patients.LastName'
        ]);
    }   
];

// Use Search Plugin
$assessmentLogs = $this->AssessmentLogs->find(
    'search', 
    $this->AssessmentLogs->filterParams($this->request->query)
);

$this->set('assessmentLogs', $this->paginate($assessmentLogs));

生成的查询

我已经包含了一些其他正常工作并返回患者姓名、类型等的关联。

SELECT 
  AssessmentLogs.AssessmentLogId AS [AssessmentLogs__AssessmentLogId], 
  AssessmentLogs.ClientID AS [AssessmentLogs__ClientID], 
  AssessmentLogs.PatientID AS [AssessmentLogs__PatientID], 
  AssessmentLogs.AssessmentTypeCd AS [AssessmentLogs__AssessmentTypeCd], 
  Clients.ClientId AS [Clients__ClientId], 
  Clients.OrganizationName AS [Clients__OrganizationName], 
  ClientEmrSystems.ClientId AS [ClientEmrSystems__ClientId], 
  ClientEmrSystems.EmrSystemId AS [ClientEmrSystems__EmrSystemId], 
  ClientEmrSystems.Created AS [ClientEmrSystems__Created], 
  ClientEmrSystems.Modified AS [ClientEmrSystems__Modified], 
  EmrSystems.ID AS [EmrSystems__ID], 
  EmrSystems.Name AS [EmrSystems__Name], 
  EmrSystems.Created AS [EmrSystems__Created], 
  EmrSystems.Modified AS [EmrSystems__Modified], 
  AssessmentTypes.AssessmentTypeCd AS [AssessmentTypes__AssessmentTypeCd], 
  AssessmentTypes.AssessmentTypeShort AS [AssessmentTypes__AssessmentTypeShort], 
  Patients.PatientId AS [Patients__PatientId], 
  Patients.FirstName AS [Patients__FirstName], 
  Patients.LastName AS [Patients__LastName]
FROM 
  AssessmentLog AssessmentLogs 
  INNER JOIN Client Clients ON Clients.ClientId = (AssessmentLogs.ClientId) 
  INNER JOIN ClientEmrSystem ClientEmrSystems ON Clients.ClientId = (ClientEmrSystems.ClientId) 
  INNER JOIN EmrSystem EmrSystems ON EmrSystems.ID = (ClientEmrSystems.EmrSystemId) 
  LEFT JOIN AssessmentType AssessmentTypes ON AssessmentTypes.AssessmentTypeCd = (
    AssessmentLogs.AssessmentTypeCd
  ) 
  LEFT JOIN Patient Patients ON Patients.PatientId = (AssessmentLogs.PatientId) 
WHERE 
  (
    EmrSystems.ID in (1) 
    AND (
      AssessmentLogs.Void = 0 
    )
  ) 
ORDER BY 
  AssessmentLogs.AssessmentLogId OFFSET 0 ROWS FETCH FIRST 40 ROWS ONLY

模式示例

CREATE TABLE [dbo].[Client](
    [ClientId] [int] NOT NULL,
    [OrganizationName] [varchar](max) NULL,
    [Email] [varchar](max) NULL,
    [WorkPhone] [varchar](max) NULL,
    [Fax] [varchar](max) NULL,
    [UpdatedDate] [datetime] NULL,
    [Notes] [text] NULL,
    CONSTRAINT [PK_Clients] PRIMARY KEY CLUSTERED 
    (
        [ClientId] ASC
    )
);

CREATE TABLE [dbo].[AssessmentLog](
    [AssessmentLogId] [int] IDENTITY(1,1) NOT NULL,
    [ClientID] [int] NOT NULL,
    [PatientID] [int] NOT NULL,
    [AssessmentTypeCd] [int] NOT NULL,
    [Note] [varchar](max) NULL,
    [Void] [bit] NOT NULL,
    [DateInserted] [datetime] NOT NULL,
    [DateCharged] [datetime] NULL,
    CONSTRAINT [PK_AssessmentLog] PRIMARY KEY CLUSTERED 
    (
        [AssessmentLogId] ASC
    )
);

CREATE TABLE [dbo].[Patient](
    [PatientId] [int] IDENTITY(1,1) NOT NULL,
    [ClientId] [int] NOT NULL,
    [FirstName] [varchar](max) NOT NULL,
    [LastName] [varchar](max) NOT NULL,
    [MedicalRecordNbr] [varchar](max) NOT NULL,
    CONSTRAINT [PK_Patient] PRIMARY KEY CLUSTERED 
    (
        [PatientId] ASC
    )
);

CREATE TABLE [dbo].[AssessmentType](
    [AssessmentTypeCd] [int] IDENTITY(1,1) NOT NULL,
    [AssessmentTypeShort] [varchar](50) NULL,
    [AssessmentTypeLong] [varchar](max) NULL,
    CONSTRAINT [PK_AssessmentType] PRIMARY KEY CLUSTERED 
    (
        [AssessmentTypeCd] ASC
    )
);

CREATE TABLE [dbo].[EmrSystem](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) NOT NULL,
    [Created] [datetime2](7) NULL,
    [Modified] [datetime2](7) NULL,
    CONSTRAINT [PK_EmrSystem] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )
);

CREATE TABLE [dbo].[ClientEmrSystem](
    [ClientId] [int] NOT NULL,
    [EmrSystemId] [int] NOT NULL,
    [Created] [datetime2](7) NULL,
    [Modified] [datetime2](7) NULL,
    CONSTRAINT [PK_ClientEmrSystem] PRIMARY KEY CLUSTERED 
    (
        [ClientId] ASC,
        [EmrSystemId] ASC
    )
);

样本记录

这是示例记录。我已经指定了主键,即使它们是自动递增/标识列,只是为了简单起见:

INSERT INTO [dbo].[Client] (
    [ClientId],
    [OrganizationName],
    [Email],
    [WorkPhone],
    [Fax],
    [UpdatedDate],
    [Notes],
) VALUES (
    123,
    'Sample Client',
    'sample@sample.com',
    '(555) 555-1234',
    '(555) 555-5678',
    '2016-12-12 12:00:00',
    'Sample notes about sample client.'
);

INSERT INTO [dbo].[Patient] (
    [PatientId],
    [ClientId], 
    [FirstName],
    [LastName],
    [MedicalRecordNbr]
) VALUES (
    1,
    123,
    'Some',
    'Dude',
    'A12345'
);

INSERT INTO [dbo].[AssessmentType] (
    [AssessmentTypeCd],
    [AssessmentTypeShort],  
    [AssessmentTypeLong]
) VALUES (
    1,
    'Sample',
    'Sample Chart'
);

INSERT INTO [dbo].[EmrSystem] (
    [ID],
    [Name], 
    [Created],
    [Modified]
) VALUES (
    1,
    'Some System',
    GETDATE(),
    GETDATE()
);

INSERT INTO [dbo].[ClientEmrSystem] (
    [ClientId], 
    [EmrSystemId],
    [Created],
    [Modified]
) VALUES (
    123,
    1,
    GETDATE(),
    GETDATE()
);  

INSERT INTO [dbo].[AssessmentLog] (
    [ClientID],
    [PatientID],
    [AssessmentTypeCd],
    [Note],
    [Void],
    [DateInserted],
    [DateCharged]
) VALUES (
    123,
    1,
    1,
    'Sample notes',
    0,
    GETDATE(),
    NULL
);

奇怪的是,当使用 EMR 系统过滤器时,Client关联下的字段也不受限制。它返回一切。我尝试调整 contains[] 数组以包含有限的字段,但所有内容都被忽略了。

我假设我做错了什么,这不是 Cake 的错,但我似乎想不出一个优雅的解决方案。感谢您的帮助:) 非常感谢。

4

0 回答 0