DBML and information hiding

Mar 3, 2010 at 9:43 AM

Did you notice that when you create an entity type in dbml (either manually or by dragging a table from server explorer), the framework by default designates every property as public?

I find this deeply disconcerting. There are several types of properties that should be made hidden (protected internal, to be precise) by default.

These include:

  • GUIDs
  • TimeStamps
  • Auto-incremented primary keys
  • foreign keys

Consider a canonical example of Customer and Order classes, with the latter containing CustomerId property. This is an FK to Customers table. There is no reason why Order.CustomerId should be made public - instead all work should be performed via Order.Customer association. I would go as far as saying that exposing Order.CustomerId is dangerous. If you look at the accessors implementation, you will notice that modifying this field directly does NOT result in updating bilateral associations (EntityRefs) between the two objects. By contrast, working with associations does it all correctly.

You may ask - So how's this related to T4? Well, in my experience no amount of telling the programmers about the best practices will make them necessarily follow them. What T4 can add is enforcement of these best practices. It takes very little effort to add to T4 a piece of logic that will throw errors if the above rules are not followed.  If you find that throwing errors is too restrictive, you can instead generate warnings.

Apart from fields accessibility there are many other properties where defaults chosen by dbml designer are questionable, at best. For example, if an entity has a TimeStamp field, it surely must have an impact on defaults for fields checking.

Of course ideally I would have preferred for dbml designer to be a bit smarter, but it is a different conversation for a different discussion group.


Mar 5, 2010 at 12:27 AM

Entity Framework took the approach of effectively hiding away foreign keys and while in many environments that works in disconnected environments such as the web it can cause other issues.

Consider the example you presented allowing the Order page to be edited. The listbox contains a drop-down list of customer names and behind the scenes it contains the PK for each. When the form is posted back to the server if you have hidden the FK field you are now forced to go to the Customers table, retrieve the customer by PK and then set the association on the Order instead of just setting the FK directly to the PK value.

Multiply this by a large number of associations and you can see what impact this would have on performance.

Setting the FK directly won't cause a problem if the navigation property hasn't been loaded and indeed LINQ to SQL's fixup mechanism will detect the change, apply it correctly and the association will appear correct.

Similar limitations occur with PK's - you need to publically expose the PK so that you can select on it when given the value - this often forms the basis of a URL request, e.g. http://orders.aspx?id=6.  Without making it public you could never issue the LINQ query Orders.Single(o => o.OrderID == id);