2016-01-20 38 views
13

Jest to wygodne, że model laravel udostępnia metodę, dzięki której może zwracać wyniki z innej powiązanej tabeli.Dlaczego model laravel powiela zbiór danych i jak (jeśli to możliwe) mieć tylko jeden zestaw danych?

Na przykład mam tabelę o nazwie item i inną tabelę o nazwie feedback, w której tabela opinii przechowuje informacje zwrotne o produkcie w tabeli pozycji. Tak więc, aby uzyskać wszystkie informacje zwrotne dotyczące elementu o identyfikatorze 1, zrobię:

Item::find(1)->feedback; 

I dalej to wydruk zwracanego obiektu.

Illuminate\Database\Eloquent\Collection Object 
( [items:protected] => Array 
     (
      [0] => Feedback Object 
       (
        [table:protected] => feedback 
        [connection:protected] => 
        [primaryKey:protected] => id 
        [perPage:protected] => 15 
        [incrementing] => 1 
        [timestamps] => 1 
        [attributes:protected] => Array 
         (
          [id] => 1 
          [rma_id] => 3 
          [item_id] => 8 
          [quo_id] => 0 
          [case_id] => i2eM20160120 
          [line_no] => 000001 
          [content] => test 
          [status] => sent 
          [read] => 0 
          [sender] => Tester 
          [created_at] => 2016-01-20 18:03:44 
          [updated_at] => 2016-01-20 18:03:44 
         ) 

        [original:protected] => Array 
         (
          [id] => 1 
          [rma_id] => 3 
          [item_id] => 8 
          [quo_id] => 0 
          [case_id] => i2eM20160120 
          [line_no] => 000001 
          [content] => test 
          [status] => sent 
          [read] => 0 
          [sender] => Tester 
          [created_at] => 2016-01-20 18:03:44 
          [updated_at] => 2016-01-20 18:03:44 
         ) 

        [relations:protected] => Array 
         (
         ) 

        [hidden:protected] => Array 
         (
         ) 

        [visible:protected] => Array 
         (
         ) 

        [appends:protected] => Array 
         (
         ) 

        [fillable:protected] => Array 
         (
         ) 

        [guarded:protected] => Array 
         (
          [0] => * 
         ) 

        [dates:protected] => Array 
         (
         ) 

        [touches:protected] => Array 
         (
         ) 

        [observables:protected] => Array 
         (
         ) 

        [with:protected] => Array 
         (
         ) 

        [morphClass:protected] => 
        [exists] => 1 
       ) 

     ) 

) 

To działa dobrze, a to pokazuje, że istnieje tylko jeden komentarz na pozycji o identyfikatorze 1.

Co dotyczy mnie to, że zestaw danych jest powielany w [attributes:protected] i [original:protected]. To tylko kwestia testowania, a prawdziwy przypadek będzie składał się z tysięcy opinii, a posiadanie powielonego zbioru danych to ogromne marnowanie pamięci. Zestaw danych nie jest duplikowany, jeśli używam podejścia DB::table('table_name'), ale jest to znacznie mniej wygodne.

Dlaczego firma laravel musi duplikować dane w modelu?

Czy istnieje sposób na zwrócenie tylko jednego zestawu danych?

Obecnie używam ->toArray() do przycinania niepotrzebnych danych zaraz po zapytaniu, ale wykorzystanie pamięci nadal istnieje, ponieważ laravel nadal tworzy ten zestaw danych.

+0

Technicznie nie trzeba używać wymowny jako ORM z laravel jest tylko to, co jest zbudowany w Jeśli nie podoba ci się sposób Eloquent generuje obiekty wtedy. użyj ORM, które Ci się podoba lub napisz swój własny kod, a następnie wyłącz Eloquent. – Pitchinnate

+0

Wszelkie sugestie dotyczące ORM? @Pitchinnate – cytsunny

+0

Nie jesteś pewien, że musiałbyś spojrzeć na wszystkie struktury, które zostały zwrócone przez różne ORMy, aby znaleźć taki, który Ci się podoba i nie masz na myśli tracenia pamięci. Największą ORM, o której wiem, że jest PHP, jest Doctrine. – Pitchinnate

Odpowiedz

4

Chociaż trudno jest uzyskać dobry przykład, pozwala to na ustawienie atrybutów przed ich definitywnym zapisaniem. Prawdopodobnie dobrze, jeśli przejdziesz przez wiele funkcji i na końcu sprawdzisz, czy wszystko zostało poprawnie ustawione dla końcowego zapisu, bez potrzeby przechowywania wszystkiego w oddzielnych zmiennych.

Bardzo mały przykład:

$user = User::find(1); 
print_r($user); 
$user->name = 'John Doe'; 
print_r($user); 
$user->save(); 
print_r($user()); 

Zwraca coś takiego:

pierwszego wydruku:

[attributes:protected] => Array 
(
    [id] => 1 
    [name] => 'Jimmy Doe' 
    ... 
) 
[original:protected] => Array 
(
    [id] => 1 
    [name] => 'Jimmy Doe' 
    ... 
) 

drugie druk:

[attributes:protected] => Array 
(
    [id] => 1 
    [name] => 'John Doe' 
    ... 
) 
[original:protected] => Array 
(
    [id] => 1 
    [name] => 'Jimmy Doe' 
    ... 
) 

Thrid druk:

[attributes:protected] => Array 
(
    [id] => 1 
    [name] => 'John Doe' 
    ... 
) 
[original:protected] => Array 
(
    [id] => 1 
    [name] => 'John Doe' 
    ... 
) 

Dopiero po save() dane są rzeczywiście zapisywane w DB.

wymownym za syncOriginal() wypala się, gdy model jest save() 'D:

/** 
* Sync the original attributes with the current. 
* 
* @return $this 
*/ 
public function syncOriginal() 
{ 
    $this->original = $this->attributes; 

    return $this; 
} 
+0

Teraz rozumiem, dlaczego tak się stało, ale czy można wyłączyć tę funkcję? (tj. zachowuje się jak normalny obiekt, nie musi zapisywać poprzedniej wartości, zapisuje tylko do bazy danych, gdy używa funkcji save()). – cytsunny

+0

Zgodnie z biblioteką, nie ma funkcji do wyłączenia tego. Ale jeśli chodzi o wydajność, możesz ograniczyć liczbę niezbędnych kluczy, uzyskując tylko potrzebny klucz, np. '$ User = User :: gdzie ('name', 'John Doe') -> get ('email');' '' Spowoduje to zmniejszenie rozmiaru tablicy. Inną opcją nie jest użycie Eumquent jako odnośnika @Pitchinnate. – Th3Alchemist

+0

Jakieś sugestie dla ORM, które robią, o czym wspomniałem? – cytsunny

3

Oryginalny dane są przechowywane w celu umożliwienia model do wykonywania brudnej sprawdzanie. Brudne sprawdzanie jest używane wewnętrznie do obsługi aktualizacji bazy danych.

Jeśli model nie jest brudny i próbujesz go zapisać, aktualizacja nie zostanie wykonana.Jeśli model jest brudny i próbujesz go zapisać, zaktualizowane zostaną tylko te brudne pola.

Jeśli naprawdę chcesz pozbyć się tego , możesz zastąpić metody syncOriginal() i syncOriginalAttribute() w modelu. Gdybyś to zrobił, oznaczałoby to, że model zawsze będzie uważany za brudny. getDirty() zawsze zwróci wszystkie atrybuty, a isDirty() zawsze zwróci true.

Jeśli używasz sygnatur czasowych, będziesz musiał również przesłonić metodę updateTimestamps(), w przeciwnym razie twoje pola updated_at i created_at nigdy nie zostaną ustawione.

class Feedback extends Model 
{ 
    // ... 

    public function syncOriginal() 
    { 
     return $this; 
    } 

    public function syncOriginalAttribute($attribute) 
    { 
     return $this; 
    } 

    protected function updateTimestamps() 
    { 
     $time = $this->freshTimestamp(); 

     $this->setUpdatedAt($time); 

     if (! $this->exists) { 
      $this->setCreatedAt($time); 
     } 
    } 

    // ... 
} 

Mogą wystąpić inne reperkusje, które nie są natychmiast widoczne w trakcie przeglądu kodu.

Powiedziawszy to wszystko, jeśli masz tę obawę dotyczącą pamięci, być może będziesz musiał przemyśleć swoje podejście i to, co próbujesz zrobić. Czy naprawdę potrzebujesz załadować 1000 informacji zwrotnych naraz? Czy jest to operacja, która może być wykonana pod chunk? Czy ta praca powinna być lepiej obsługiwana przez poszczególne zadania w kolejce? etc ...

3

To powinno być nie powinno być problemem biorąc pod uwagę sposób, w jaki PHP działa wewnętrznie. Dopóki "atrybuty" nie zostaną zmodyfikowane, "atrybuty" są jedynie wskaźnikiem do "oryginału" (lub odwrotnie), więc posiadanie obu tablic zajmuje prawie taką samą ilość pamięci, jak tylko jedna z nich. Dlatego użycie pamięci nie zmienia się, gdy wykonujesz toArray().

Proszę zobaczyć ten link do szczegółów: http://blog.ircmaxell.com/2014/12/what-about-garbage.html