Tharos / LeanMapper

Lean Mapper is a tiny ORM based on powerful Dibi database abstraction library for PHP.
MIT License
87 stars 35 forks source link

best practice for deleting from m:belongsToMany #70

Open achtan opened 10 years ago

achtan commented 10 years ago

Ahoj,

ako spravne managovat kolekcie v LM ?

/**
 * @property int $id
 * @property Bar[] $bars m:belongsToMany
 */
class Foo extends Entity
{

}

/**
 * @property int $id
 */
class Bar extends Entity
{

}

ked upravujem kolekciu:

$foo = $this->fooRepository->find($id);

$this->barRepository->deleteById($barId);

$bars = $foo->getBars();

na poslednom riadku to hodi vinimku: Cannot get value of property 'bars' in entity Foo due to low-level failure: It is not allowed to create entity Bar from detached instance of LeanMapper\Row

priblizne chapem co sa tam deje, len by ma zaujimalo ako sa tomu vyhnut a ako riesit taketo situacie

Tharos commented 10 years ago

Ahoj,

kde se přesně bere to $barId? Je to ID jednoho prvku získaného při přístupu k $foo->bars?

Oblast, o které píšeš, je v Lean Mapperu taková asi nejslabší. V podstatě jde o to, že LM při managementu odkazující kolekce není o nich chytřejší, než Dibi, NotORM nebo NDBT… Pokud už máš zinicializované kolekce a něco se v podstatě na pozadí změní v databázi (byť přes ORM), tu zinicializovanou kolekci to nijak neovlivní.

Nejsnazším řešením je načíst po úpravách z databáze $foo podle PK znovu, čímž vznikne nová entita bez zinicializovaných kolekcí. Pokud bych měl poradit něco sofistikovanějšího, potřeboval bych komplexnější ukázku (alespoň v jaké posloupnosti se co děje).

Nicméně, na výjimku, kterou jsi popsal, by se asi ideálně nikdy nemělo narazit, takže jsi asi zároveň narazil na use case, který zatím ještě není úplně odlazený. Tím spíš by se mi hodila výřečnější ukázka, abych si to snadno mohl zpreprodukovat. :) Rád se tím budu ještě zabývat.

achtan commented 10 years ago

tak som pripravil test ktory vlastne nieje test :) ale len ukazka kodu kt. hadze tu chybu #71

Tharos commented 10 years ago

Díky za skvěle připravenou ukázku! V neděli se vrátím z dovči, a tak se pak všem věcem od Tebe budu věnovat. :)

Tharos commented 10 years ago

První věcí, kterou můžeme udělat, je povolit vytvoření instance entity z detached Row. Aktuální omezení je umělé – z počátku jsem netušil, kdy by se vytvoření entity takovýmto způsobem mohlo hodit, ale Ty jsi objevil use case, ve kterém by to smysl mělo.

Jdeme-li v úvahách dále, mně osobně vyvstávají zajímavé otázky: má po smazání záznamu z databáze ta entita v kolekci nadále figurovat nebo ne? Pro její zahození mluví to, že se přece provedl nějaký delete, ale pro její zachování mluví to, že ta entita i poté stále ještě existuje v paměti a odkazuje na tu hlavní entitu. Doufám, že to popisuji stravitelně…

Nedělám si iluze, že by Lean Mapper šlo nějak jednodušše upravit, aby tohle nějak komplexně řešil. Tohle už se prostě neobejde bez identity map a nějakých chytrých kolekcí. Jediné, co tedy aktuálně můžu doporučit, je výše popsaný styl práce (v podstatě jako kdyby bylo použité Dibi nebo NotORM). Vnímám to jako daň za jeho (relativní) jednoduchost, tenkost. Rozhodně se ale nebráním žádným nápadům, jak jeho chování vylepšit, pokud by někdo vymyslel něco geniálního. :)

achtan commented 10 years ago

upravujem kod testu #71

$authorRepository = new AuthorRepository($connection, $mapper, $entityFactory);
$bookRepository = new BookRepository($connection, $mapper, $entityFactory);

$author = $authorRepository->find(3);

foreach($author->books as $book) {
    if($book->id == 5) {
        $bookRepository->delete($book);
        $author->removeBook($book); // odstrani knihu s kolekcie
    }
}

Assert::equal(1, count($author->books));

toto by bolo narocne na implementaciu? ze by samotna entyta vedela spravovat svoje kolekcie... obdobne to riesi aj Doctrine 2