What actually prevents SQL injection?
Parameterised queries. The statement and the data travel to the database separately, so the driver never has to decide where a value ends and syntax begins — which is precisely the ambiguity injection exploits. Escaping is a fragile imitation of that, because it depends on getting every character class and encoding right in a language you do not control. The same rule generalises: never build a command out of string concatenation with untrusted input.
Where it still bites in an ORM: raw fragments, dynamic ORDER BY, and table names — none of which can be bound as parameters, so they need an allowlist.