We’re excited to announce that the Azure Tables libraries have been released for .NET, Java, JavaScript/TypeScript, and Python. The Azure Table service stores NoSQL data in the cloud with a key/attribute store schema-less design. The Table storage service can be used to store flexible data sets like user data for web applications, address books, device information, or other types of metadata.
The new libraries follow our Azure SDK Guidelines, making for an idiomatic, consistent, approachable, diagnosable, and dependable library. The new libraries use the language-specific Azure Core packages for handling requests, errors, and credentials.
Note: The Azure Tables libraries are capable of targeting both Azure Storage Table and Azure Cosmos DB Table API endpoints.
SDK Availability
The Azure Tables libraries can be downloaded from each languages preferred package manager.
Language | Package | Command | Project Home | Getting Started |
---|---|---|---|---|
Python | PyPi | pip install azure-data-tables |
link | link |
.NET | NuGet | dotnet add package Azure.Data.Tables |
link | link |
JavaScript/TypeScript | npm | npm install @azure/data-tables |
link | link |
Java | Java | Add to POM.xml file | link | link |
This blog post assumes you have a working developer environment for your preferred programming language and you already have a Storage or Cosmos Table account. If you do not have those refer to the Getting Started entry in the above table for your preferred programming language. To follow along with these snippets you’ll need the programming language of your choice (Python, .NET, Java, JS) installed, a text editor, and a Storage or Cosmos Table account.
There will be migration guides added to each project’s homepage that will show specific examples for updating your code base to the new Azure Tables library discussed in this blog. Links to complete code examples for each language are provided at the end of the article.
Creating the clients
There are two clients for interacting with the service. The TableServiceClient
can be used for account-level interactions (creating tables, setting and getting access policies) and the TableClient
is used for table-level interactions (create or delete an entity, query or list entities). You can create clients with a key, Shared Access Signature, or using a connection string, all of which can be found in the Azure Portal.
Python
table_client = TableClient.from_connection_string("<your-connection-string>", "officeSupplies")
table_service_client = TableServiceClient.from_connection_String("<your-connection-string>")
.NET
TableClient client = new TableClient("connectionString", "officeSupplies");
TableServiceClient serviceClient = new TableServiceClient("connectionString");
Java
TableClient tableClient = new TableClientBuilder()
.connectionString("<your-connection-string>")
.tableName("officeSupplies")
.buildClient();
JavaScript
const client = TableClient.fromConnectionString("<your-connection-string>", "officeSupplies");
Create a table and add an entity to it
Table names can be any alphanumeric string between 3 and 63 characters. A table can be created from either the TableClient
or the TableServiceClient
, the following snippets will show how to create one from a TableClient
.
An Entity can contain up to 255 properties, with the three system properties of PartitionKey
, RowKey
, and Timestamp
. The first two properties must be provided on all entities and the Timestamp
property will be modified by the service. For more information, see the service documentation. Entities can only be inserted and queried from the TableClient
.
Python
table_client = TableClient.from_connection_string("<your-connection-string>", "myTable")
table_client.create()
my_entity = {
"PartitionKey": "markers",
"RowKey": "id-001",
"Product": "Markers",
"Price": 5.00,
"Count": 10,
"Available": True
}
table_client.create_entity(my_entity)
.NET
var tableClient = new TableClient(
new Uri(serviceUri),
tableName,
new TableSharedKeyCredential(accountName, storageAccountKey));
tableClient.Create();
var partitionKey = "markers";
var rowKey = "id-001";
var entity = new TableEntity(partitionKey, rowKey)
{
{ "Product", "Marker Set" },
{ "Price", 5.00 },
{ "Quantity", 21 }
};
tableClient.AddEntity(entity);
Java
TableClient tableClient = new TableClientBuilder()
.connectionString("<your-connection-string>")
.tableName(tableName)
.buildClient();
String partitionKey = "markers";
String rowKey = "id-001";
TableEntity entity = new TableEntity(partitionKey, rowKey)
.addProperty("Product", "Marker Set")
.addProperty("Price", 5.00)
.addProperty("Quantity", 21);
tableClient.createEntity(entity);
JavaScript
const tableName = "SampleCreateAndDeleteTable2";
const client = TableClient.fromConnectionString("<your-connection-string>", tableName);
await client.createTable();
const entity = {
partitionKey: "p1",
rowKey: "r1",
date: new Date()
};
await client.createEntity(entity);
Querying Table Entities
The TableClient
allows the user to create custom queries using OData filters. For more information on writing table and entity queries check out the service documentation.
Python
query_filter = "PartitionKey eq @pk_filter or RowKey eq @rk_filter"
parameters = {
"pk_filter": "markers",
"rk_filter": "id-001",
}
for entity in table_client.query_entities(query_filter, parameters=parameters):
print(entity["Product"], entity["Count"])
.NET
string MyPK = "markers";
string MyRK = "id-001";
string filter = TableOdataFilter.Create($"PartitionKey eq {MyPK} or RowKey eq {MyRK}")
Pageable<TableEntity> entities = tableClient.Query<TableEntity>(filter: filter);
foreach (TableEntity entity in entities)
{
Console.WriteLine($"{entity.GetString("Product")}: {entity.GetInteger("Count")}");
}
Java
ListEntitiesOptions options = new ListEntitiesOptions()
.setFilter("PartitionKey eq 'markers' or RowKey eq 'id-001'");
for (TableEntity entity : tableClient.listEntities(options)) {
Map<String, Object> properties = entity.getProperties();
System.out.println(String.format("%s: %d", properties.get("Product"), properties.get("Count")));
}
JavaScript
const partitionKey = "markers";
const id = "id-001"
let entities = client.listEntities({ queryOptions: { filter: odata`PartitionKey eq ${partitionKey} or RowKey eq ${id}` });
for await (const entity of entities) {
console.log(`${entity.Product}: ${entity.Count}`);
}
Batch Transactions
The Table service allows multiple entity operations (create, delete, update, and upsert) to be made in a single request using transactional batch operations. The transaction is an “all-or-nothing” approach, if there is a failure in one of the operations, the entire operation will fail. A transaction can perform any combination of create, delete, update, and upsert operations. For more information, see the service documentation.
Note: All operations within a transaction must target the same partition key.
Python
table_client = TableClient.from_connection_string("<your-connection-string>", "myProductTable")
entity1 = {"PartitionKey": "pk0001", "RowKey": "A1", "Name": "Marker Set", "Price": 5.0, "Quantity": 21}
entity2 = {"PartitionKey": "pk0001", "RowKey": "A2"}
entity3 = {"PartitionKey": "pk0001", "RowKey": "A3", "Name": "Pen Set", "Price": 2.0, "Quantity": 6}
entity4 = {"PartitionKey": "pk0001", "RowKey": "A4", "Name": "Pencil", "Price": 1.5, "Quantity": 100}
operations = [
("upsert", entity1),
("delete", entity2),
("create", entity3),
("update", entity4, {"mode": "replace"})
]
table_client.submit_transaction(operations)
.NET
var tableClient = new TableClient(
new Uri(serviceUri),
tableName,
new TableSharedKeyCredential(accountName, storageAccountKey));
string partitionKey = "BatchInsertSample";
List<TableEntity> entityList = new List<TableEntity>
{
new TableEntity(partitionKey, "01")
{
{ "Product", "Marker" },
{ "Price", 5.00 },
{ "Brand", "Premium" }
},
new TableEntity(partitionKey, "02")
{
{ "Product", "Pen" },
{ "Price", 3.00 },
{ "Brand", "Premium" }
},
new TableEntity(partitionKey, "03")
{
{ "Product", "Paper" },
{ "Price", 0.10 },
{ "Brand", "Premium" }
},
new TableEntity(partitionKey, "04")
{
{ "Product", "Glue" },
{ "Price", 1.00 },
{ "Brand", "Generic" }
},
};
// Create the batch.
List<TableTransactionAction> addEntitiesBatch = new List<TableTransactionAction>();
// Add the entities to be added to the batch.
addEntitiesBatch.AddRange(entityList.Select(e => new TableTransactionAction(TableTransactionActionType.Add, e)));
// Submit the batch.
Response<IReadOnlyList<Response>> response = await client.SubmitTransactionAsync(addEntitiesBatch).ConfigureAwait(false);
for (int i = 0; i < entityList.Count; i++)
{
Console.WriteLine($"The ETag for the entity with RowKey: '{entityList[i].RowKey}' is {response.Value[i].Headers.ETag}");
}
Java
TableClient tableClient = new TableClientBuilder()
.tableName("myProductTable")
.connectionString("<your-connection-string>")
.buildClient();
// Now let's create a list to add transactional batch actions to.
List<TableTransactionAction> transactionActions = new ArrayList<>();
String partitionKey = "pk001";
TableEntity firstEntity = new TableEntity(partitionKey, "rk001")
.addProperty("Name", "Marker Set")
.addProperty("Price", 5.0)
.addProperty("Quantity", 21);
TableEntity secondEntity = new TableEntity(partitionKey, "rk002")
.addProperty("Brand", "Crayola")
.addProperty("Color", "Blue");
TableEntity entityToUpdate = new TableEntity(partitionKey, "rk003")
.addProperty("Brand", "Crayola")
.addProperty("Color", "Red");
TableEntity entityToDelete = new TableEntity(partitionKey, "rk004")
.addProperty("Brand", "Crayola")
.addProperty("Color", "Green");
transactionActions.add(new TableTransactionAction(TableTransactionActionType.CREATE, firstEntity));
transactionActions.add(new TableTransactionAction(TableTransactionActionType.CREATE, secondEntity));
transactionActions.add(new TableTransactionAction(TableTransactionActionType.UPDATE_MERGE, entityToUpdate));
transactionActions.add(new TableTransactionAction(TableTransactionActionType.DELETE, entityToDelete));
TableTransactionResult tableTransactionResult = tableClient.submitTransaction(transactionActions);
JavaScript
// See authenticationMethods sample for other options of creating a new client
const client = TableClient.fromConnectionString("<your-connection-string>", "tableName");
const partitionKey = "Stationery";
// Create a transaction
const transaction = new TableTransaction();
// Add actions to the transaction
transaction.createEntity({
partitionKey,
rowKey: "A1",
name: "Marker Set",
price: 5.0,
quantity: 21
});
transaction.createEntity({
partitionKey,
rowKey: "A2",
name: "Pen Set",
price: 2.0,
quantity: 6
});
transaction.createEntity({
partitionKey,
rowKey: "A3",
name: "Pencil",
price: 1.5,
quantity: 100
});
// Submit the transaction using the actions list built by the helper
const transactionResult = await client.submitTransaction(transaction.actions);
Conclusion
We hope this was a valuable technical introduction to Azure Tables
and what you can use today to build and ship rich experiences.
If you want to learn more and get started, here are some quick links to our official documentation:
- .NET documentation and .NET samples
- Java documentation and Java samples
- JavaScript/TypeScript documentation, JS samples, and TS samples
- Python documentation and Python samples
References
Azure SDK Blog Contributions
Thank you for reading this Azure SDK blog post! We hope that you learned something new and welcome you to share this post. We are open to Azure SDK blog contributions. Please contact us at azsdkblog@microsoft.com with your topic and we’ll get you set up as a guest blogger.
Azure SDK Links
- Azure SDK Website: aka.ms/azsdk
- Azure SDK Intro (3 minute video): aka.ms/azsdk/intro
- Azure SDK Intro Deck (PowerPoint deck): aka.ms/azsdk/intro/deck
- Azure SDK Releases: aka.ms/azsdk/releases
- Azure SDK Blog: aka.ms/azsdk/blog
- Azure SDK Twitter: twitter.com/AzureSDK
- Azure SDK Design Guidelines: aka.ms/azsdk/guide
- Azure SDKs & Tools: azure.microsoft.com/downloads
- Azure SDK Central Repository: github.com/azure/azure-sdk
- Azure SDK for .NET: github.com/azure/azure-sdk-for-net
- Azure SDK for Java: github.com/azure/azure-sdk-for-java
- Azure SDK for Python: github.com/azure/azure-sdk-for-python
- Azure SDK for JavaScript/TypeScript: github.com/azure/azure-sdk-for-js
- Azure SDK for Android: github.com/Azure/azure-sdk-for-android
- Azure SDK for iOS: github.com/Azure/azure-sdk-for-ios
- Azure SDK for Go: github.com/Azure/azure-sdk-for-go
- Azure SDK for C: github.com/Azure/azure-sdk-for-c
- Azure SDK for C++: github.com/Azure/azure-sdk-for-cpp
Dear Sean, thank you for the detailed examples and the introduction. The choice of the library name is somewhat unfortunate - there is already a DataTable class in System.Data namespace and this might just lead to confusion. I would also like to point out that in the post you are referring to a .NET as a language. This is clearly wrong as .NET is not a language. All the examples are given in the C#...
Since years I would love to use it to store mass data. But still, because there is no delete protection or backup function for Azure Table storage, it's not useable in production. Cosmos DB is still way to expensive to store TBs of data. Table Storage would be the perfect time series serving layer for use, but without backup... 😰 And I do not expect that to change because there is no evolution for Table...