sql >> Database >  >> RDS >> Mysql

behoortToMany-relatie in Laravel over meerdere databases

Heel eenvoudig:

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

Ik verkrijg de databasenaam dynamisch omdat mijn verbinding is geconfigureerd op basis van een omgevingsvariabele. Laravel lijkt aan te nemen dat de draaitabel in dezelfde database bestaat als de doelrelatie, dus dit zal het dwingen om in plaats daarvan te kijken naar de database die overeenkomt met het model waarin deze methode zich bevindt, uw 'A'-rijk.

Als u zich geen zorgen maakt over SQLite-databases, d.w.z. in het kader van een unit-test, is dat alles wat u nodig heeft. Maar als dat zo is, blijf dan lezen.

Ten eerste is het vorige voorbeeld op zichzelf niet voldoende. De waarde van $database zou uiteindelijk een bestandspad zijn, dus je moet het een alias geven naar iets dat een SQL-instructie niet verbreekt, en het toegankelijk maken voor de huidige verbinding. "ATTACH DATABASE '$database' AS $name" zo doe je dat:

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');
}

Waarschuwing:transacties verpesten dit: Als de huidige verbinding transacties gebruikt, mislukt de instructie ATTACH DATABASE. Je kunt gebruik transacties erop na het uitvoeren van die verklaring wel.

Terwijl, als de gerelateerde verbinding transacties gebruikt, worden de resulterende gegevens stil onzichtbaar gemaakt voor de huidige. Dit maakte me langer gek dan ik zou willen toegeven, omdat mijn vragen zonder fouten liepen, maar steeds leeg bleven. Het lijkt erop dat alleen gegevens die echt naar de bijgevoegde database zijn geschreven, daadwerkelijk toegankelijk zijn voor de database waaraan ze zijn gekoppeld.

Dus nadat je gedwongen bent om naar je bijgevoegde database te schrijven, wil je misschien nog steeds dat je test zichzelf opruimt. Een eenvoudige oplossing zou zijn om gewoon $this->artisan('migrate:rollback', ['--database' => $attachedConnectionName]); te gebruiken . Maar als je meerdere tests hebt die dezelfde tabellen nodig hebben, is dit niet erg efficiënt, omdat ze hierdoor gedwongen worden om ze elke keer opnieuw op te bouwen.

Een betere optie zou zijn om de tabellen af ​​te kappen, maar hun structuur intact te laten:

//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'");
    });
}

Hiermee worden alle gegevens van die verbinding gewist , maar er is geen reden waarom u daar niet een soort filter op zou kunnen toepassen, zoals u dat wilt. Als alternatief kunt u profiteren van het feit dat SQLite DB's gemakkelijk toegankelijke bestanden zijn en de bijgevoegde naar een tijdelijk bestand kopiëren en deze gebruiken om de bron te overschrijven nadat de test is uitgevoerd. Het resultaat zou functioneel identiek zijn aan een transactie.



  1. mysql importeren op windows

  2. Verwijder dubbele rijen in MySQL (negert primaire sleutel)

  3. AWS RDS-back-upmethoden

  4. Hoe het MySQL-tekencoderingsprobleem op te lossen?