All the above but just let me emphasize the obvious - No spinning up ado.net and hacking in rows
At runtime there are a LOT of caches we use. In the ‘update pipeline’ in ICE we handle the cache refreshes for a module, notify other app servers in a cluster, etc. If you go at the db directly, none of that fires so the app thinks the data is X and db thinks the data is Y and the other app servers in the cluster think the data is Z. Great way to start a timebomb that blows up 5 minutes or 5 days later and everyone pulls out their hair trying to figure out what happened because the db access was done days or hours before.
The other aspect is the usage in calculated columns in local or remote tables. Module developers can ‘tap into’ that pipeline as well and when they see field 1 being changed, they update field 17 in their table. This will not occur with a direct db access and now the application code is corrupt and time bomb is set again to blow up hours or days later (or fiscal year end - that’s always a fun one to do root cause analysis on months later)