Laravel Eloquent ManyToMany с Pivot, вторичный запрос с переменными в сводной таблице? - PullRequest
0 голосов
/ 10 февраля 2019

Я немного поиграл с Laravel и натолкнулся на странный крайний случай, который я не могу понять

У меня следующая структура таблицы:

CREATE TABLE `community_address` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `address_id` int(10) unsigned NOT NULL,
  `community_id` int(10) unsigned NOT NULL,
  `is_billing` tinyint(1) NOT NULL DEFAULT '1',
  `is_service` tinyint(1) NOT NULL DEFAULT '1',
  `is_mailing` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
)

CREATE TABLE `communities` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
)

CREATE TABLE `addresses` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `address_1` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Street address',
  `address_2` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Street adddress 2 (Company name, Suite, etc)',
  `city` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'City',
  `state` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'State / Province',
  `zip` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Zip / Postal Code',
  `country_id` int(10) unsigned NOT NULL COMMENT 'Country ID',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
)

То, что я представил с помощью следующей модели Laravel для сообщества

class Community extends Model
{
    public function addresses(){
        return $this->belongsToMany(Address::class, 'community_address', 'community_id',  'address_id');
    }
}

$ community-> address (), на самом деле возвращает только адреса для сообщества, но я хочу отфильтровать по типу адреса в моемсводная таблица (биллинг, рассылка и т. д.)

Я могу попробовать это:

   public function getBillingAddress(){
        return $this->addresses()->wherePivot('is_billing','=', true)->firstOrFail()->get();
    }

, которая возвращает результаты, однако КАЖДАЯ строка в моей сводной таблице соответствует моему запросу, но не выполняет мой запросот существующих адресов

Поэтому моей второй идеей было использование логического аргумента 'и' следующим образом:

 public function getBillingAddress(){
        return $this->addresses()->wherePivot('community_id', '=', $this->id, true)->wherePivot('is_billing','=', true)->firstOrFail()->get();
    }

, что приводит к следующему SQL, который выдает ошибки (по очевидным причинам), нотакже не совсем похоже, что он ищет то, что я хотел бы, даже если бы оно работало?

select `addresses`.*, `community_address`.`community_id` as `pivot_community_id`, `community_address`.`address_id` as `pivot_address_id` from `addresses` inner join `community_address` on `addresses`.`id` = `community_address`.`address_id` where `community_address`.`community_id` = 2 1 `community_address`.`community_id` = 2 and `community_address`.`is_billing` = 1 limit 1 

Что мне кажется, что значение "and" на самом деле не является логическим значением, но печатает значение в виде строкиght к запросу.

Я попробовал очевидное и попытался поменять четвертый аргумент на «и», и был сгенерирован следующий sql, который не дает сбоя, но возвращает все адреса, а не только адреса, связанные смое сообщество

select `addresses`.*, `community_address`.`community_id` as `pivot_community_id`, `community_address`.`address_id` as `pivot_address_id` from `addresses` inner join `community_address` on `addresses`.`id` = `community_address`.`address_id` where `community_address`.`community_id` = 2 and `community_address`.`community_id` = 2 and `community_address`.`is_billing` = 1 limit 1)

Я что-то упускаю здесь очевидное?

При некотором манипулировании с результатом SQL я могу получить то, что хочу, а именно следующий необработанный SQL-запрос:

select `addresses`.*,
       `community_address`.`community_id` as `pivot_community_id`,
       `community_address`.`address_id`   as `pivot_address_id`
from `addresses`
       inner join `community_address` on `addresses`.`id` = `community_address`.`address_id` and `community_address`.`community_id` = 2 and `community_address`.`is_billing` = 1
limit 1

Как я могу получить тот же SQL, сгенерированный для меня через eloquent?

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

Кажется, я неправильно понял, как работал wherePivot(), изменив код на следующее:

   public function getBillingAddress(){
        return $this->addresses()->wherePivot('is_billing', '=', true)->get()->first->all();
    }

Где новый код пытается вызвать столбец is_billing сводной таблицы для дальнейшей фильтрации существующихТаблица, старый пытался отфильтровать его по тому, по которому он уже был отфильтрован, но поскольку это было внутреннее соединение, он возвращал все строки (по крайней мере, я так думаю?)

В любом случае, эторешено, надеюсь, это поможет кому-то в будущем.

0 голосов
/ 10 февраля 2019

Я думаю, что это будет полезно для вас. Если я приведу пример, у нас есть Пользователи Роль И Role_User Таблицы, к которым мы подключаемся Пользователи К Роль с принадлежностью ко многим И мы хотим использовать select:

Модели пользователей:

function Roles()
{
 return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
}

в нашем контроллере мы можем написать любой выбор, как показано ниже:

class exampleController extends Controller
{
public function index()
{
User::with(['Roles'=>function($query){$query->where(....)->get();}])->get(); 
}

}

Вы можете использовать любой выбор по запросу и вернуть то, что вы хотите ..

просто будьте осторожны, если вам нужно использовать любую переменную в вашем выборе, вы должны использовать нижеформат

class exampleController extends Controller
{
public function index()
{
$var =...;
User::with(['Roles'=>function($query) use ($var){$query->where(....,$var)->get();}])->get(); 
}

}

надеюсь, это решит вашу проблему ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...