Laravel JOIN Проблема с SQLSTATE [23000]: нарушение ограничения целостности: 1052 Столбец 'album_id' в списке полей неоднозначен - PullRequest
0 голосов
/ 11 марта 2020

Я ссылался на другие вопросы, такие как мой, но я не могу понять, почему я получаю ошибку в моем примере.

У меня есть 3 таблицы. nn_album, nn_song и сводная таблица nn_song_album_song

Имена моих таблиц имеют имена nn_album.album_id, nn_song.song_id, сводная таблица имеет идентификатор в качестве первичного ключа и одинаковые имена столбцов "song_id" и "album_id"

100 * Я могу добавить альбом, но когда я хочу добавить новую песню в альбом, я получаю эту ошибку при функции сохранения ...

SQLSTATE [23000]: Нарушение ограничения целостности: 1052 Столбец 'album_id' в списке полей неоднозначен (SQL: выберите album_id из nn_album внутреннее объединение nn_song_album_song в nn_album. album_id = nn_song_album_song. album_id, где nn_song_album_song. song_id = 21)

Модель моей песни

public function albums()
{
    return $this->belongsToMany('App\Albums', 'nn_song_album_song', 'song_id', 'album_id');
}

Модель моего альбома

public function songs()
{
    return $this->belongsToMany('App\SongDetail', 'nn_song_album_song', 'song_id', 'album_id');
}

Мой контроллер Функция сохранения

$albums = request('albums');

if ($song_id>0)
{
    $entry = SongDetail::where('song_id', $song_id)->firstOrfail();
    $entry->update($data);
    $entry->albums()->sync($albums);
}
else
{
    $entry = SongDetail::create($data);
    $entry->albums()->attach($albums);
}

Мой вид на стороне администратора для выбора входного альбома (я могу выбрать несколько альбомов для добавления)

<div class="form-group form-float mainalbum" style="margin-bottom: 45px;border-bottom: solid 1px;">
    <div class="form-line">


        <select class="form-control show-tick" name="albums[]" id="albums" data-live-search="true" >

            @foreach($albums as $album)
                @if($album->album_id != 1)<option value="{{ $album->album_id }}" {{ collect(old('albums', $album))->contains($album->album_id) ? 'selected': '' }}>
                    {{ $album->album_name }}</option>@endif
            @endforeach


        </select>
        <select class="albums2" name="albums2[]" id="albums2" multiple>
            @foreach($albums as $album)
                @if($album->album_id != 1)<option value="{{ $album->album_id }}" {{ collect(old('albums', $album))->contains($album->album_id) ? 'selected': '' }}>
                    {{ $album->album_name }}</option>@endif
            @endforeach
        </select>
    </div>

</div>

У вас есть идеи, что здесь происходит? В чем моя вина? Если вы поделитесь со мной своими мыслями, я ценю вас.

Спасибо.

Ответы [ 3 ]

1 голос
/ 13 марта 2020

Ну, вы действительно сделали вещи намного сложнее, чем нужно, назвав все в соответствии с Laravel соглашениями. Если бы это было настроено должным образом, у вас были бы модели с именами Album и Song, хранящиеся в таблицах базы данных albums и songs, с сводной таблицей с именем album_song. Тогда все было бы намного проще.

Но эти соглашения можно обойти, если один читает документацию :

Как упоминалось ранее, для определения имени таблицы Eloquent объединит две таблицы названий моделей в алфавитном порядке. Тем не менее, вы можете изменить это соглашение. Вы можете сделать это, передав второй аргумент методу belongsToMany.

Помимо настройки имени присоединяемой таблицы, вы также можете настроить имена столбцов ключей таблицы, передав дополнительные аргументы. к методу belongsToMany. Третий аргумент - это имя внешнего ключа модели, для которой вы определяете отношение, а четвертый аргумент - это имя внешнего ключа модели, к которой вы присоединяетесь.

Итак, исправляя ваши аргументы, мы получаем:

class SongDetail extends Model
{
    public function albums()
    {
        return $this->belongsToMany('App\Albums', 'nn_song_album_song', 'song_id', 'album_id');
    }
}

class Albums extends Model
{
    public function songs()
    {
        return $this->belongsToMany('App\SongDetail', 'nn_song_album_song', 'album_id', 'song_id');
    }
}

Что должно правильно определять отношения. Ваш контроллер снова нарушает соглашение, так как Laravel контроллеры ресурсов обычно определяют отдельные методы для хранения и обновления. Но я могу сделать одно предложение, чтобы очистить код, который вы показали:

$albums = request('albums');

try {
    $entry = SongDetail::findOrFail($song_id);
    $entry->update($data);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
    $entry = SongDetail::create($data);
}
$entry->albums()->sync($albums);

И, на ваш взгляд, если вы хотите передать массив значений, вам нужно указать multiple в <select> element.

0 голосов
/ 17 марта 2020

Хорошо, что указывает на сообщение об ошибке sql то, что album_id существует в обеих таблицах, но вы выбираете album_id без указания того, какой вы хотите, следовательно, это неоднозначно

Вы, скорее всего, можете решить эту проблему, вместо этого укажите точный столбец в строке

return $this->belongsToMany('App\Albums', 'nn_song_album_song', 'song_id', 'album_id');

, изменив его на

return $this->belongsToMany('App\Albums', 'nn_song_album_song', 'nn_song_album_song.song_id', 'nn_song_album_song.album_id');

. Я не на 100% использую это решение, поскольку для меня это не самый знакомый синтаксис, но указание Таблица для выходных параметров должна решить проблему. Возможно, вам придется применить это к обеим моделям. Фактическое решение может быть вариацией этого, но вы решите это путем более точного указания имен таблиц для полей в ваших запросах, используя синтаксис точек, упомянутый здесь и в других ответах.

0 голосов
/ 11 марта 2020

Когда вы объединяете две таблицы, она также объединяет имена столбцов. Вы должны описать, из какой таблицы вы хотите взять столбец album_id. например, nn_album.album_id или nn_song_album_song.album_id

Ваш запрос sql должен выглядеть следующим образом: select nn_album.album_id from nn_album inner join nn_song_album_song on nn_album.album_id = nn_song_album_song.album_id where nn_song_album_song.song_id = 21

...