Anchor 4 Breaking Changes

Tortuga Anchor has traditionally not seen a lot of churn. Other than the big rewrite for Nullable Reference Type support, the name has changed more frequently than the API. With apologies, I have to discuss a couple breaking changes for Anchor 4.

Public Does Not Mean Public

The first the is the way metadata is handled. The Tortuga.Anchor.Metadata namespace was designed as a wrapper around .NET reflection. In addition to convenience methods, it includes a caching layer so that expensive reflection calls only have to be made once.

Something that isn’t always obvious is the idea that .NET reflection isn’t the same thing as “C# reflection”. While similar, .NET reflection uses slightly different terminology. For example, “public” in .NET reflection means “This can be seen outside of the assembly”. That includes not only public properties in the CE #, but also C#’s properties marked with the protected keyword.

The correct way of handling this is to check both the IsPublic and IsFamily flags on a MethodInfo object, the latter being the marker for protected members.

A Bad Design Decision

The second issue is TableAndView attribute. To understand this, first a little background.

In .NET there is a Table attribute used to indicate which database table a given class relates to. While well known in Entity Framework, it isn’t actually an EF concept and many other ORMs including Tortuga Chain rely on it.

Since reading reflection data is expensive, Anchor caches the Table attribute values, as well as related ones such Key, Column, and NotMapped.

Since most databases have some sort of namespacing option, the Table attribute also includes an optional Schema property.

So far so good. But when trying to use it, you realize that reading directly form the table is annoying. What you would rather do is read from a view that pre-joins all of the lookup tables that you might need. But when you do your writes, you still need the underlying table. (Just the one, you generally don’t want to modify the lookup tables.) For most ORMs this would require having two DTOs and tedious mapping code between them.

Anchor and Chain took a different route. By introducing a TableAndView attribute, you could indicate that reads come from a view while writes go to the table in the same schema.

And that’s where I messed up. I assumed that the view would also be in the same schema as the table, so I just made TableAndView inherit from Table and added a view name property.

I could ‘fix’ this by adding a view schema property to the attribute, but that would be confusing. It would probably still be a breaking change unless I carefully thought through every possible combination of using schema and view schema. And if there is a break, it would be subtle.

So I opted for the easier, and arguably more correct, route of just deprecating TableAndView. It is replaced by a View attribute with its own name and schema attributes. The old attribute will hang around for the time being, but if you have both the new one will take priority.

Leave a Reply

Your email address will not be published. Required fields are marked *