2016-04-08 12 views
5

mam do czynienia z następującą sytuacją: Mam dwóch modeli, co stanowi Employee z id i name pól i Telephone z id, employee_id i flag dziedzinach. Między tymi dwoma modelami istnieje również między jednym modelem , tzn. Pracownik może mieć wiele telefonów, a telefon może należeć do jednego pracownika.Zapytania za pomocą wielu połączeń z bazą danych MySQL w laravel 5,2

class Employee extends Model 
{ 
    public function telephones() 
    { 
     return $this->hasMany(Telephone::class); 
    } 
} 



class Telephone extends Model 
{ 
     public function employee() 
    { 
     return $this->belongsTo(Employee::class); 
    } 
} 

Model Employee odwołuje się do tabeli employees że istnieje w schemacie bazy danych o nazwie mydb1, podczas gdy model Telephone dotyczy telephones tabeli, która istnieje w innym schemacie bazy danych o nazwie mydb2.

Co chcę jest pobrać tylko pracownikom przynajmniej jeden telefon określonej flagi chętny załadowanego, stosując wymowne i (jeśli to możliwe), nie Konstruktora kwerend

Co próbowałem tak daleko bez sukcesu jest:

1) użyć metody whereHas w kontrolerze

$employees = Employee::whereHas('telephones', function ($query) { 

    $query->where('flag', 1); //Fetch only the employees with telephones of flag=1 

})->with([ 

    'telephones' => function ($query) { //Eager load only the telephones of flag=1 

     $query->where('flag', 1); 
    } 

])->get(); 

Co staram się zrobić tutaj jest pierwszy pobrać tylko pracowników, które mają telefony z flaga = 1, a drugi do upragnieniem obciążeniu tylko te telefony, ale pojawia się następujący wyjątek zapytania z powodu różnych stosowane połączenia db: tabela

bazowa lub widok nie znaleziono: mydb1.telephones tabela nie istnieje (i to telefony istnieje mydb2)

2) ładunek Eager z więzów w kontrolerze

$employees = Employee::with([ 

    'telephones' => function ($query) { 

     $query->where('flag', 1); 
    }, 

])->get(); 

Metoda ta chętnie ładuje telefony z flaga = 1, ale zwraca wszystkie instancje pracownika, który nie jest to, czego naprawdę chcą. Chciałbym mieć tylko modele pracowniczych, które są w telefon z flag = 1 Zbiór , z wyłączeniem modeli z telephones = []

+0

Tylko sugestia, ale może mógłbyś zrobić [widok] (http://dev.mysql.com/doc/refman/5.7/en/view-syntax.html) w jednej z twoich baz danych, która scala '' pracowników i "telefony", a następnie wyciągnąć z widoku w swoim kodzie. Także [zobacz dyskusję na temat łączenia baz danych w MySQL] (http://stackoverflow.com/questions/1565993/oracle-database-link-mysql-equivalent). – Richard

+0

Czy ustawiłeś chronione $ connection = 'mydb2'; do modelu telefonu? – Froxz

+0

@Froxz tak, ale niestety whereHas() nie bierze tego pod uwagę – ira

Odpowiedz

2

Uwzględniając this post, this post i @Giedrius Kiršys odpowiedzieć poniżej, ale w końcu wymyślił rozwiązanie, które pasuje do moich potrzeb, wykonując następujące czynności:

  1. stworzenie sposobu, który zwraca się obiekt Powiązania w modelu
  2. chętnie obciążenia ten nowy związek w kontrolerze
  3. odfiltrowane telefonów flagi! = 1, stosując zakres zapytania w modelu

W Pracownik modelu

/** 
* This is the new relationship 
* 
*/ 
public function flaggedTelephones() 
{ 
    return $this->telephones() 
     ->where('flag', 1); //this will return a relation object 
} 



/** 
* This is the query scope that filters the flagged telephones 
* 
* This is the raw query performed: 
* select * from mydb1.employees where exists (
* select * from mydb2.telephones 
* where telephones.employee_id = employee.id 
* and flag = 1); 
* 
*/  
public function scopeHasFlaggedTelephones($query, $id) 
{ 
    return $query->whereExists(function ($query) use ($id) { 
     $query->select(DB::raw('*')) 
      ->from('mydb2.telephones') 
      ->where('telephones.flag', $flag) 
      ->whereRaw('telephones.employee_id = employees.id'); 
    }); 
} 

w kontrolerze

Teraz mogę korzystać z tej elegancki składni a'la wymowny

$employees = Employee::with('flaggedTelephones')->hasFlaggedTelephones()->get(); 

który czyta się jak „Fetch wszystkich pracowników z telefonów Oznaczone chętny załadowany, a następnie podjąć tylko pracowników, które mają co najmniej jeden telefon oznaczony”

EDIT:

Po pracy z frameworkiem Laravel przez chwilę (obecna wersja używana 5.2.39), stwierdziłem, że w rzeczywistości klauzule whereHas() działają w przypadku, gdy model relacji istnieje w innej bazie danych przy użyciu metody from(), ponieważ jest to przedstawiono poniżej:

$employees = Employee::whereHas('telephones', function($query){ 

    $query->from('mydb2.telephones')->where('flag', 1); 

})->get(); 

@Rob Contreras kredytów stwierdzające stosowanie metody from(), jednak wygląda na to metoda wymaga, aby wziąć zarówno bazę danych i tabelę jako argument.

1

Nie wiem, czy to będzie działać, ale można skorzystać z metody, aby określić połączenie z bazą danych w zamknięcie:

$employees = Employee::whereHas('telephones', function($query){ 

    $query->from('mydb2')->where('flag', 1); 

})->get(); 

Nadzieja to pomaga

+0

Dziękuję za odpowiedź, ale niestety to nie wystarczyło. Proponowana przez ciebie propozycja faktycznie wybiera tabelę o nazwie "db2", która znajduje się w domyślnym połączeniu bazy danych "db1": Zobacz błąd: SQLSTATE [42S02]: Nie znaleziono tabeli podstawowej lub widoku: 1146 Tabela "mydb1.mydb2" nie istnieje (SQL: wybierz * z 'directorates', gdzie istnieje (wybierz * z' mydb2' gdzie 'telefony''directorate_id' =' directorates' .id' i 'flag' = 5)). – ira

+0

zobacz moją ostatnią edycję, związaną z użyciem metody 'from', dziękuję – ira

1

Brudny rozwiązanie:

Zastosowanie whereExists i zakres fo r lepsza czytelność.

w modelu Employee umieścić:

public function scopeFlags($query, $flag) 
{ 
    $query->whereExists(function ($q) use ($flag) { 
     $q->select(\DB::raw(1)) 
      ->from('mydb2.telephones') 
      ->where('telephones.flag', $flag) 
      ->whereRaw('telephones.employee_id = employees.id'); 
    }); 
} 

Następnie zmodyfikować zapytanie tak:

$employees = Employee::flags(1)->get(); 
+0

bardzo dziękuję @Giedrius Kiršys, skończyłem z tym samym zapytaniem, aby odfiltrować oflagowane telefony (np.' Wybierz * z mydb1.pracownicy tam, gdzie istnieje (wybierz * z mydb2.telephones, gdzie telephones.employee_id = employee.id i flag = 1')). Jednak muszę też mieć naładowane telefony oznaczone flagą. – ira

Powiązane problemy