During a discussion this weekend I realized that a lot of the complexity of DAL and ORM projects stems from the attempt to accomplish both needs in the same library. And, perhaps, that makes sense; it might be argued that the only pragmatic difference is cache strategy and thus certain data and/or object properties can cause one to tread into the other's territory.
For example, a Data Access Layer that requires read (and possibly write) caching needs to address functionally similar needs as an ORM. Similarly, an Object-Relational Mapping that represents a wide and/or deep collection of objects may similar benefit from read/write caching as a means of dynamically loading/unloading/persisting data in order to minimize memory or network usage or provide disaster recovery (e.g., autosave).
Arguably, DALs should be intrinsically driven from the database up. They are fundamentally databases which may be exposed to multiple clients representing different security, usage and optimization needs. Similarly, the database may be required to enforce data integrity amongst multiple clients (e.g., it may act as the write master). Effective DALs should expose the innate benefits of the underlying database structure; for example, they should enforce relationships and constraints and, more importantly, allow queries to be performed that work with data (e.g., SQL) as opposed to objects (e.g., OOP). For instance, one might expect a search method in a DAL to proxy the request to a backend SQL server which is more optimized to filtering sets based on queries against particular indexes.
Again, however, these boundaries become more ambiguous when working with caching. For example, depending on the data, a DAL implementing read caching may benefit from highly optimized in-memory indexes for querying the object tree by common search criteria to avoid unnecessary round-trips to the database. In some cases, if the DAL benefits from agressive write caching (assuming versioning is not an issue), it may necessitate this in order to ensure the search is working against the latest data.
Ultimately, as with most programming challenges, there is no universal solution. Ignia has written, for instance, object models that are simply serialized and persisted to disk; this is a simple "ORM" that works well for many needs. In other instances, Ignia has written libraries that effectively act as a dynamic query assembler for SQL, providing generic non-object-driven access to a complex database for unknown requirements (typically used for administrative and search tools where performance and security are trumped by the need for flexibility and rapid development). And, of course, most fall in between - object models which perform varying levels of caching with varying levels of dependencies on in-memory optimization vs. pass-through relays to the underlying data storage structure.
In this regard, having a variety of methods for approaching the challenges of an ORM or DAL make the most sense. A risk of code-generation libraries is that many fundamentally assume certain requirements and thus are optimized for needs which may not match your own. Understanding a project's specific requirements as well as the strengths and weaknesses of multiple ORM or DAL-generation solutions mitigates this problem, albeit at the consequence of requiring the knowledge (and possibly maintenance) of multiple tools. For example, at Ignia we often home-brew DALs, ORMs or hybrids for specific projects - while other times we use LINQ or .netTiers depending on our specific needs.