sql >> Databáze >  >> RDS >> Mysql

PatříToMany vztah v Laravel napříč více databázemi

Velmi jednoduše:

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

Název databáze získávám dynamicky, protože moje připojení je nakonfigurováno na základě proměnné prostředí. Zdá se, že Laravel předpokládá, že kontingenční tabulka existuje ve stejné databázi jako cílový vztah, takže to jej přinutí podívat se místo toho na databázi odpovídající modelu, ve kterém je tato metoda, ve vaší oblasti 'A'.

Pokud se nebojíte SQLite databází, tedy v rámci unit-testu, to je vše, co potřebujete. Ale pokud ano, čtěte dál.

Za prvé, předchozí příklad sám o sobě nestačí. Hodnota $database by skončila jako cesta k souboru, takže ji musíte přiřadit k něčemu, co nenaruší příkaz SQL, a zpřístupnit to aktuálnímu připojení. "ATTACH DATABASE '$database' AS $name" jak to děláte:

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

Upozornění:Transakce to zhoršují: Pokud aktuální připojení používá transakce, příkaz ATTACH DATABASE selže. můžete používat transakce na něm po provedením tohoto příkazu.

Vzhledem k tomu, pokud souvisí připojení používá transakce, výsledná data budou tiše zneviditelněna pro aktuální. To mě přivádělo k šílenství déle, než bych si chtěl přiznat, protože mé dotazy běžely bez chyby, ale stále přicházely prázdné. Zdá se, že pouze data skutečně zapsaná do připojené databáze jsou skutečně přístupná té, ke které jsou připojena.

Takže poté, co jste byli nuceni zapisovat do připojené databáze, možná budete chtít, aby se váš test po sobě vyčistil. Jednoduchým řešením by bylo použít pouze $this->artisan('migrate:rollback', ['--database' => $attachedConnectionName]); . Ale pokud máte více testů, které potřebují stejné tabulky, není to příliš efektivní, protože je to nutí je pokaždé znovu sestavit.

Lepší možností by bylo zkrátit tabulky, ale jejich strukturu ponechat v platnosti:

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

Tímto vymažete všechna data z daného připojení , ale není důvod, proč byste na to nemohli použít nějaký druh filtru, jak uznáte za vhodné. Alternativně můžete využít toho, že SQLite DB jsou snadno dostupné soubory a jednoduše zkopírovat připojený do dočasného souboru a použít jej k přepsání zdroje po provedení testu. Výsledek by byl funkčně identický s transakcí.



  1. Najděte délku nejdelšího řádku ve sloupci v oracle

  2. Nejlepší PG Clustering řešení vysoké dostupnosti pro PostgreSQL

  3. Jak vytvořit pohledy historie NEBO auditování z tabulek pro zachycení změn dat (CDC) na serveru SQL Server - kurz SQL Server

  4. Jak převést UTC na místní čas v MySQL