Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Relacja należy do wielu w Laravel w wielu bazach danych

Bardzo prosto:

public function bs()
{
    $database = $this->getConnection()->getDatabaseName();
    return $this->belongsToMany('B', "$database.a_bs", 'a_id', 'b_id');
}

Otrzymuję nazwę bazy danych dynamicznie, ponieważ moje połączenie jest konfigurowane na podstawie zmiennej środowiskowej. Laravel wydaje się zakładać, że tabela przestawna istnieje w tej samej bazie danych, co relacja docelowa, więc to zmusi ją do spojrzenia na bazę danych odpowiadającą modelowi, w którym znajduje się ta metoda, w dziedzinie „A”.

Jeśli nie martwisz się bazami danych SQLite, tj. w zakresie testu jednostkowego, to wszystko, czego potrzebujesz. Ale jeśli tak, czytaj dalej.

Po pierwsze, poprzedni przykład sam w sobie nie jest wystarczający. Wartość $database stałaby się ścieżką do pliku, więc musisz przypisać jej alias do czegoś, co nie zepsuje instrukcji SQL i udostępnić ją dla bieżącego połączenia. "ATTACH DATABASE '$database' AS $name" jak to robisz:

public function bs()
{
    $database = $this->getConnection()->getDatabaseName();
    if (is_file($database)) {
        $connection = app('B')->getConnection()->getName();
        $name = $this->getConnection()->getName();
        \Illuminate\Support\Facades\DB::connection($connection)->statement("ATTACH DATABASE '$database' AS $name");
        $database = $name;
    }
    return $this->belongsToMany('B', "$database.a_bs", 'a_id', 'b_id');
}

Ostrzeżenie:Transakcje to wszystko psują: Jeśli bieżące połączenie korzysta z transakcji, instrukcja ATTACH DATABASE nie powiedzie się. możesz korzystać z transakcji po wykonanie tego oświadczenia.

Natomiast jeśli pokrewne połączenie wykorzystuje transakcje, wynikowe dane będą po cichu niewidoczne dla bieżącego. To doprowadzało mnie do szału na dłużej, niż chciałbym przyznać, ponieważ moje zapytania działały bezbłędnie, ale wciąż pojawiały się puste. Wygląda na to, że tylko dane naprawdę zapisane w dołączonej bazie danych są w rzeczywistości dostępne dla tej, do której są dołączone.

Tak więc, po zmuszeniu do zapisu do dołączonej bazy danych, możesz nadal chcieć, aby test po sobie posprzątał. Prostym rozwiązaniem byłoby użycie $this->artisan('migrate:rollback', ['--database' => $attachedConnectionName]); . Ale jeśli masz wiele testów, które wymagają tych samych tabel, nie jest to zbyt wydajne, ponieważ zmusza ich do konieczności ich odbudowy za każdym razem.

Lepszym rozwiązaniem byłoby przycięcie tabel, ale pozostawienie ich struktury bez zmian:

//Get all tables within the attached database
collect(DB::connection($database)->select("SELECT name FROM sqlite_master WHERE type = 'table'"))->each(function ($table) use ($name) {
        //Clear all entries for the table
        DB::connection($database)->delete("DELETE FROM '$table->name'");
        //Reset any auto-incremented index value
        DB::connection($database)->delete("DELETE FROM sqlite_sequence WHERE name = '$table->name'");
    });
}

Spowoduje to wyczyszczenie wszystkich danych z tego połączenia , ale nie ma powodu, dla którego nie można by zastosować do tego filtru, jakkolwiek uznasz to za stosowne. Alternatywnie możesz skorzystać z faktu, że bazy danych SQLite są łatwo dostępnymi plikami i po prostu skopiuj załączony plik do pliku tymczasowego i użyj go do nadpisania źródła po zakończeniu testu. Wynik byłby funkcjonalnie identyczny z transakcją.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Serwer napotkał błąd wewnętrzny lub nieprawidłową konfigurację i nie mógł zrealizować Twojego żądania

  2. Sortowanie wielu pól w MySQL

  3. BŁĄD 2002 (HY000):Nie można połączyć się z lokalnym serwerem MySQL przez gniazdo '/var/run/mysqld/mysqld.sock' (2)

  4. Zapytanie do tabeli przestawnej MySQL z dynamicznymi kolumnami

  5. MySQL/MariaDB:utwórz widok tabeli przestawnej