--- breadcrumb: - FAQ summary-order: 5 keywords: - faq - troubleshooting - help - common --- # ❓ FAQ ## Entities
How does Hector ORM map an entity class to a database table? By default, the **class name** (without namespace) is converted to **snake_case**. For example, `UserProfile` maps to the `user_profile` table. You can override this with the `#[Orm\Table]` attribute: ```php use Hector\Orm\Attributes as Orm; #[Orm\Table('my_custom_table')] class User extends Entity {} ``` See [Entities — How entities map to tables](orm/entity.md#%EF%B8%8F-how-entities-map-to-tables) for details.
What is the difference between Magic Entity and Classic Entity? **Magic Entity** (`MagicEntity`) uses PHP's `__get`/`__set` magic methods — properties are dynamic. Minimal boilerplate, but no IDE autocompletion or static analysis. **Classic Entity** (`Entity`) uses explicitly declared PHP properties. Better IDE support and easier to maintain. Both support the same features (relationships, save, delete, etc.). The choice depends on your preference for explicitness vs. brevity. See [Entities](orm/entity.md) for a full comparison.
My entity is not saved to the database — what could be wrong? Common causes: 1. **You forgot to call `save()`** — Creating an entity and setting properties does not persist it automatically. 2. **The ORM is not booted** — Make sure `OrmFactory::orm(...)` has been called before any entity operation. 3. **The table name does not match** — Check that the snake_case version of your class name matches a table in the configured schema, or use `#[Orm\Table('...')]` explicitly. 4. **A before-save event stopped propagation** — If you use a PSR-14 event dispatcher, check that no listener calls `stopPropagation()` on `EntityBeforeSaveEvent`. See [Events](orm/events.md).
What is the difference between save() and Orm::get()->persist()? `Entity::save()` persists the entity **immediately** (one database query per call). `Orm::get()->save($entity)` (without `persist: true`) marks the entity for saving but does **not** execute the query. You must call `Orm::get()->persist()` to flush all pending operations in a single transaction. See [Entities — Deferred persistence](orm/entity.md#deferred-persistence-unit-of-work) for details.
--- ## Queries
How do I debug the SQL queries generated by Hector ORM? Enable the query logger on your `Connection`: ```php use Hector\Connection\Connection; use Hector\Connection\Log\Logger; $logger = new Logger(); $connection = new Connection( dsn: 'mysql:host=localhost;dbname=mydb', username: 'root', password: 'secret', logger: $logger, ); // ... run your queries ... foreach ($logger->getLogs() as $log) { echo $log->getStatement() . "\n"; print_r($log->getParameters()); echo $log->getDuration() . "ms\n"; } ``` See [Connection — Query logging](components/connection.md#-query-logging).
How do I avoid N+1 queries with relationships? Use eager loading with `with()` on the query builder: ```php $users = User::query() ->with(['posts', 'profile']) ->all(); ``` This loads the related entities in a single batch query instead of one query per entity. For entities that are already loaded, use `load()`: ```php $user = User::find(1); $user->load(['posts']); ``` See [Builder — Eager loading](orm/builder.md) and [Entities — Loading relations on-demand](orm/entity.md#loading-relations-on-demand).
--- ## Schema & cache
Schema introspection is slow — how do I speed it up? Use a PSR-16 cache implementation to persist schema metadata across requests: ```php $orm = OrmFactory::orm( options: ['schemas' => ['my_database']], connection: $connection, cache: $psr16Cache, ); ``` The schema will be introspected once, cached, and reused on subsequent requests. See [Cache](orm/cache.md).
When should I clear the schema cache? Clear the cache whenever your database schema changes — typically **after running migrations** or manually altering tables. ```php $cache->clear(); // or delete the specific key: $cache->delete('HECTOR_ORM'); ``` Integrate this into your deployment pipeline, right after database migrations.
--- ## Migrations
Can I roll back a migration? Only if the migration implements `ReversibleMigrationInterface` and provides a `down()` method. The runner will throw a `MigrationException` if you try to revert a non-reversible migration. ```php $runner->down(steps: 1); // Revert the last migration ``` See [Migration](components/migration.md).
In what order are migrations executed? Migrations are executed in the order provided by the migration provider: - **`DirectoryProvider`**: files are sorted alphabetically by filename. Use a timestamp prefix (e.g. `20260101000000_CreateUsers.php`) to control the order. - **`Psr4Provider`**: classes are sorted alphabetically by FQCN. - **`ArrayProvider`**: order of insertion. See [Migration — Providers](components/migration.md#-providers).