I read this post last night, and I noticed it was from 2006. I could go either way on the ORM, database thing, but I was just wondering if everything bad Jeff said about OR
Disclosure: I'm the author of RDO.Net.
Yes. I believe existing ORMs are going in the wrong direction - they're trying to map relational data into arbitrary objects which IMHO is simply not possible. In the OO world, the arbitrary object is not serialization/deserialization friendly, because every object has an object reference (the address) that is local to the current process. It's OK when you're dealing with a single object, you will get into trouble when you're facing a complex object graph.
Hopefully this problem can be solved using a different approach, as in RDO.Net: instead of mapping relational data into arbitrary objects, we map the schema of the data as rich metadata (Model
that contains columns, primary/foreign keys, validations, etc.), and expose concrete Db
, DbTable
, DbQuery
and DataSet
for data access. When performing database CRUD operations, you construct the SQL Abstract Syntax Tree (AST) explicitly using strongly typed OO language, as demonstrated in the following sample C# code, which creates a query and returns a DataSet for hierarchical data:
public async Task<DataSet<SalesOrderInfo>> GetSalesOrderInfoAsync(_Int32 salesOrderID, CancellationToken ct = default(CancellationToken))
{
var result = CreateQuery((DbQueryBuilder builder, SalesOrderInfo _) =>
{
builder.From(SalesOrderHeader, out var o)
.LeftJoin(Customer, o.FK_Customer, out var c)
.LeftJoin(Address, o.FK_ShipToAddress, out var shipTo)
.LeftJoin(Address, o.FK_BillToAddress, out var billTo)
.AutoSelect()
.AutoSelect(c, _.Customer)
.AutoSelect(shipTo, _.ShipToAddress)
.AutoSelect(billTo, _.BillToAddress)
.Where(o.SalesOrderID == salesOrderID);
});
await result.CreateChildAsync(_ => _.SalesOrderDetails, (DbQueryBuilder builder, SalesOrderInfoDetail _) =>
{
builder.From(SalesOrderDetail, out var d)
.LeftJoin(Product, d.FK_Product, out var p)
.AutoSelect()
.AutoSelect(p, _.Product)
.OrderBy(d.SalesOrderDetailID);
}, ct);
return await result.ToDataSetAsync(ct);
}
Yes.
Object-oriented is still object-oriented and Relational is still Set-oriented. Nothing has changed in these two paradigms in the past two years to make them work better together.
In many people's eyes, SQL is ugly, complex, and confusing. But trying to make an object-oriented interface to perform the same functionality is always uglier, more complex, and has a steeper learning curve.
In all programming, there is a tradeoff between flexibility and assumptions. Frameworks (such as Rails) try to solve the problem by being "opinionated." That is, they limit flexibility of either the relational or the object-oriented aspects of the problem, making assumptions about how data is structured, and what operations you can do with it. Naturally, simplifying the problem space makes the solution simpler as well.
In addition, it's frustrating to discover that an ORM framework is incomplete, so some ordinary operations in SQL have no solution in a given ORM. This is also a consequence of "opinionated" frameworks.
I think it does.
I think the last sentence is the most interesting of all: "I tend to err on the side of the database-as-model camp, because I think objects are overrated." Java, C++, and C# are certainly the dominant languages, but functional programming is making a comeback with F#, Scala, etc.
This isn't my area of expertise, but I worked in Rails for about a year and I think ActiveRecord solved most of the DB Mapping problem. I realize it has a few issues, but I think it did a fantastic job.
I don't think his post took into account the possibility of the framework itself (in this case AcitveRecord/Rails) defining the database AND the Object Model, which--as far as I can tell--makes the problem go away.
Since this is the opposite of the first two responses (basically that the post is outdated) I feel like I'm probably not understanding something; If that's the case please correct me instead of just voting me down because I think there is an important point I'm missing.
I think starting from the assumption that Jeff's conclusions are correct is not necessarily good; having maintained stored procedure code as well as JDBC-based data layers, I can say that these caused maintenance problems galore, mostly related to the inability to understand what was going on at a higher level.
A database is necessarily low-level; it stores numbers and strings essentially. Business logic is high-level. This is why we have abstraction.
Personally, I think the Rails/ActiveRecord way is the best solution to having an object/domain model but also being able to take advantage of a relational database.
So: don't throw out ORM, but don't default to it either. It's a tool that solves certain problems. To ignore it would be ignorant and to always use it would be arrogant.
I can only speak for my experience. I use DAL and DTO's, and I am still capable of performing pretty complex queries (joins and all), and also I am able to resort to SP's or custom SQL whenever I need. It made my life easier, my code consistent and my deadlines more attainable.