We moved this to a private TFS repository just after creating this - I've left this version behind for anyone who wants to get the drift of the original idea.
This is very much a work in progress - don't judge me, yet!
AzureTableFramework is an object mapper that enables .NET developers to work with Azure Table data using domain-specific objects. It eliminates the need for most of the data-access code that developers usually need to write. (...or what I wanted EF7 to do for Azure Tables - In all fairness, Azure Tables are different enough from SQL Tables that it deserves its own library seperate from a SQL-based EF).
Written in .Net Core (compatible with the full framework), it utilizes the official WindowsAzure.Storage API > 6.2.2, Dependency Injection.
- Indexing / Azure Search Integration
- Parent / Child Relationships
- (Azure Storage) Blob & Queue Support
- Backups
- Encryption
- Required / Unique / Field Validation
Download the nugetpackage (coming soon), define your classes and call them in context (in a familiar EF-like way).
public class BloggingContext : AzureTablesContext
{
public AzureTableDictionary<Blog> Blogs { get; set; }
public AzureTableDictionary<Post> Posts { get; set; }
}
public class Blog : AzureTableEntity
{
[PartitionKey]
public string AuthorID { get; set; }
//RowKey
public string BlogID { get; set; }
public string Url { get; set; }
public Dictionary<string, Post> Posts { get; set; }
}
public class Post : AzureTableEntity
{
[PartitionKey]
public string BlogID { get; set; }
//RowKey
public string PostID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
Save
using (var DB = new BloggingContext())
{
var BLOG = DB.Blogs.New();
BLOG.AuthorID = "HughesJeff";
await DB.SaveChangesAsync();
}
Get
using (var DB = new BloggingContext())
{
var B = await DB.Blogs.GetAsync("Blog1");
Debug.WriteLine("B.Url = " + B?.Url);
}
There are a few key differences in using this library than you are probably used to;
If you don't read any other documentation, read this next section ...
Tables are created auto-magically, there are no database create/update migration tasks All you need are azure storage credentials. When "SaveChanges" is called, tables that don't exist will be created.
Tables are named after Classes (public class Blog {} => "Blog" Table ) If you change a class name (and please don't forget it's corresponding ID property name, too), a new table will be created the next time "SaveChanges" is called and previous data will remain in the old table with the old class name. There is no migration.
RowKeys are ClassNames + "ID" There must be a (string) property that matches the case-sensitive pattern Class Name + "ID" (e.g. class named Blog, must have a (string) property of "BlogID"). RowKeys are GUIDs by default, if you don't otherwise populate the property, a new guid (as string) will be created before saving.
public class Blog : AzureTableEntity
{
...
//RowKey
public string BlogID { get; set; }
...
}
Storage Classes must inherit : AzureTableEntity
- RowKey, PartitionKey, and ETag come from the Official API : EntityTable.
- LastUpdated and a few other goodies come from this library : AzureTableEntity (which inherits EntityTable).
Azure Tables require PartitionKeys to be defined! (Think of it as less of a burden and more like a free index) If you don't decorate one (string) property in each class with a [PartitionKey] attribute; an error will be thrown. I suggest using a foriegn key propery and situating it above the ID property. Results will eventually be returned sorted by PartitionKey, then RowKey alphanumerically.
Code-First Only!
You probably won't be able to find the columns for Class + "ID" and whatevery property you decorated with [PartitionKey] in the storage table There's no reason to save the data twice. So, in the table, the data from the Class Name + "ID" property is removed and saved as the RowKey column and the data in the property decorated by [PartitionKey] is removed from that property and saved as the PartitionKey column. The data is restored to the appropriate field from storage.
public class Blog : AzureTableEntity
{
[PartitionKey]
public string AuthorID { get; set; }
//RowKey
public string BlogID { get; set; }
public string Url { get; set; }
public Dictionary<string, Post> Posts { get; set; }
}
So, Blog Table will look like this:
PartitionKey | RowKey | Timestamp | Url |
---|---|---|---|
HughesJeff | Blog1 | 1 Jan 2016 2:30PM | Url1 |
HughesJeff | Blog2 | 1 Jan 2016 4:30PM | Url2 |
instead of this:
PartitionKey | AuthorID | RowKey | BlogID | Timestamp | Url |
---|---|---|---|---|---|
HughesJeff | HughesJeff | Blog1 | Blog1 | 1 Jan 2016 2:30PM | Url1 |
HughesJeff | HughesJeff | Blog2 | Blog2 | 1 Jan 2016 4:30PM | Url2 |
🔺 Duplicate 🔺 | 🔺 Duplicate 🔺 |
The library handles the deduping and reconstruction, behind the scenes.
AzureTableDictionary.Items stores a dictionary retreivable by ID -- Using Items.New() adds a GUID (as a string) automatically, and adds the item to the items list by that GUID. If you change the ID property value, it won't be automagically reflected in the Items keys list.
DB.Blogs.Items["Blog1"]
POCO defined data access
I LOVE AZURE TABLES!
For TCO (for most data needs), AzureTables beats every other database.
AzureTableFramework | |
---|---|
Website | http://AzureTableFramework.com |
Documentation | http://azuretableframework.rtfd.org |
GitHub Repository | https://github.com/JeffHughes/AzureTableFramework.git |
Owner | Jeff Hughes (me@jeffhughes.com) |
First Version | created 5 Jan 2016 |