Hayden.ActiveRecord Concurrency and 1:1, 1:m, and m:m Relationships - O/R Mapper
by David Hayden ( Sarasota Florida ), Filed: O/R Mappers
Busting my butt all week and decided to take a break and update my Hayden.ActiveRecord O/R Mapper this weekend so I could use it on a new project.
I talked about my ActiveRecord O/R Mapper before in a couple of posts:
The previous version of Hayden.ActiveRecord had a pretty decent set of features that allows me to query the database using a number of constructs as you can see from a quick look at the API via intellisense:
Queries are pretty simple and fairly flexible using Expression or Query Objects, and you can do things like record paging, etc. I also use a Fluent Interface for query construction which keeps things even easier. All-in-all, some pretty decent flexibility by simply inheriting from an ActiveRecordBase Class ( actually this is not a requirement but just how I use it ) and adding attributes to class properties:
[Table("Posts")]
public class Post : ActiveRecordBase<Post,int>
{
[Column(Id = true, AutoGen = true)]
public int PostId
{
get { return _postId; }
set { _postId = value; }
}
[Column]
public int BlogId
{
get { return _blogId; }
set { _blogId = value; }
}
[Column]
public string Title
{
get { return _title; }
set { _title = value; }
}
}
A couple of limitations of the previous version, however:
- Only Supported 2 Concurrency Options: OverwriteChanges and Timestamp
- Row updates updated everything, not just changes
The legacy database I am using on this new project would have caused me some real pain, because 1) the customer wants reasonable concurrency protection but I am not allowed to add a timestamp, and 2) the tables have lots of columns which causes more issues with concurrency as well as large update commands hitting the database.
So, this weekend I added 2 new features to help with this situation
- Column/Property Change Tracking
- 3rd Concurrency Option: CompareChangedValues
You can read more about optimistic concurrency options in a post of mine:
What this is giving me now is more intelligent updates and concurrency that is not reliant on a Timestamp. Here is an example of an update when only the title of a Post was changed using the CompareChangedValues Concurrency Option:
Update Posts
Set
Title = @Title
Where
PostID = @PostID
AND
Title = @TitleOrig
Pretty basic stuff I realize, but it requires a way to keep track of changes and original values retrieved from the database. There are several ways to pull this off. I went for the simplest and less memory intensive form that tracks only changes to the entity. The bad news is that it requires even more noise on my classes. In this case, a call to a MarkDirty in the property setter:
[Column]
public string Title
{
get { return _title; }
set
{
if (_title.Equals(value))
return;
MarkDirty("Title", _title);
_title = value;
}
}
I know - yuck! I realize there are a lot of arguments why this is not ideal and I know them all, but for now this will work fine until I add other less evasive options.
While I was in there, I also added the beginnings of optional support for relationships. Hence above where you see a column called BlogId, which is the PK of a record in the blogs table, one can now get true relationship mapping for 1:1, 1:m, and m:m relationships. In the Post class you can toss out the BlogId Property and add the following instead
private Blog _blog;
[HasOne]
public Blog Blog
{
get { return _blog; }
set { _blog = value; }
}
I have added [HasOne], [HasMany], and [HasManyToMany] attributes to work with various options. Right now there is no lazy-loading and not a helluva lot of intelligence built into it in terms of query optimization. Each relationship attribute causes another roundtrip to the database during reads. I have to do a bit more head scratching and testing before I use this in the wild, but I wanted to get in there so I can start using it on my personal websites.
Anyway, it was just good to update my ActiveRecord Framework because it hasn't received much love the past 6 months. I'll probably spend a few more weekends this month polishing and finishing up these wave of features. I would like to get support for stored procedures this month, too.
Source: David Hayden ( Sarasota Florida )
Filed: O/R Mappers