多量のデータを安価に取り扱うとしてたらAzure Table Strage一択になります。本日はレシートデータ(これから多量に保存されるだろうと思われるもの)を保存しながら利用方法を紹介します。
TableStorage?
Table Storageとは何ぞや、というのはこちらを参照ください。
設計のワンポイント
ポイントとしては、RowKey
(ID)とPartitionKey
という2軸があり、PartitionKey
である程度データをグルーピングしておくこで取込パフォーマンスは著しくあがります。今回のようにレシートデータを保存する場合はStoreId
をPartiotionKey
とすることでStore単位である程度データをまとめて取得することができるようにしています。
SDK
.NET用にライブラリーがありますのでそちらを利用します。NuGetはこちら。
Tableの作成
まずは一番上位にあるテーブルを作成します。CreateTableIfNotExists
というこで、なければ新しく作成されることなく該当のテーブルを参照することができます。TableItem
を返すファンクションにしておくことによって毎度これを呼べるようにしておきます。
private TableItem CreateTable(string tableName)
{
var serviceClient = new TableServiceClient(new Uri(_storageUri),
new TableSharedKeyCredential(_storageAccountName, _storageAccountKey));
TableItem table = serviceClient.CreateTableIfNotExists(tableName);
return table;
}
TableClientの作成
実際にテーブルに対してなにか操作したい場合はTableClient
が必要となります。なので、こちらもTableClient
を返すファンクションをここで書いておきます。
private TableClient GetTableClient(string tableName)
{
var tableClient = new TableClient(
new Uri(_storageUri),
tableName,
new TableSharedKeyCredential(_storageAccountName, _storageAccountKey));
// Create the table in the service.
tableClient.Create();
return tableClient;
}
データの挿入
次はテーブルにデータを挿入します。データモデルはITableEntity
を継承します。
少し長いですが、これが実際につかったモデルになります。
/// <summary>
/// Receipt
/// </summary>
public class ReceiptModel : ITableEntity
{
public ReceiptModel(string id,
string transactionType, string terminalTransactionId, DateTime terminalTransactionDateTime,
string storeId, string terminalId, string staffId,
decimal subTotal,
decimal grandTotal
)
{
RowKey = id;
TransactionType = transactionType;
TerminalTransactionId = terminalTransactionId;
TerminalTransactionDateTime = terminalTransactionDateTime;
PartitionKey = storeId;
TerminalId = terminalId;
StaffId = staffId;
SubTotal = subTotal;
GrandTotal = grandTotal;
}
// Id and Type
public string RowKey { get; set; }
public string TransactionType { get; set; }
public string? CancelType { get; set; }
public string TerminalTransactionId { get; set; }
public DateTime TerminalTransactionDateTime { get; set; }
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; }
// Store, Terminal, Staff
public string PartitionKey { get; set; } // StoreId
public string TerminalId { get; set; }
public string StaffId { get; set; }
// Customer
public string? CustomerId { get; set; }
public string? CustomerCode { get; set; }
public string? CustomerGroup { get; set; }
public DateTime TimeOfEnter { get; set; }
public int NumberOfParty { get; set; }
public string? CustomerMemo { get; set; }
// Sub Total
public decimal SubTotal { get; set; }
public decimal SubTotalDiscountAmount { get; set; }
public int SubTotalDiscountRate { get; set; }
// Points
public string? NameOfPoint { get; set; }
public int PointsUsed { get; set; }
public int PointsAdded { get; set; }
public int TotalPointsAfetr { get; set; }
public int TotalPointsBefore { get; set; }
public PointAsTypes PointAs { get; set; }
// Miles
public string? NameOfMile { get; set; }
public int MilesUsed { get; set; }
public int MilesAdded { get; set; }
public int MilesPointsAfetr { get; set; }
public int MilesPointsBefore { get; set; }
public string? MilesNote { get; set; }
// Tax
public int TaxPercentageIfInclude { get; set; }
public int TaxPercentageIfExclude { get; set; }
// Round or Not
public int RoundingPosition { get; set; }
public int RoundingMethod { get; set; }
// Otehr Fee
public decimal ShippingFee { get; set; }
public decimal ServiceFee { get; set; }
public decimal OtherFee { get; set; }
// Grand Total
public decimal GrandTotal { get; set; }
// Deposit and Change
public DepositMethodTypes DespoitMethod { get; set; }
public decimal Deposit { get; set; }
public decimal Change { get; set; }
// Closing
public bool IsClosed { get; set; }
public DateTime ClosingDate { get; set; }
// Memo
public string? Memo { get; set; }
public string? Tags { get; set; }
public string? Barcode { get; set; }
// Designs
public string? BackgroundColor { get; set; }
public string? ForeColor { get; set; }
public string? HeaderContentHtml { get; set; }
public string? AfterItemsContentHtml { get; set; }
public string? AfterGrandTotalContentHtml { get; set; }
public string? AfterPaymentMethodContentHtml { get; set; }
public string? FooterContentHtml { get; set; }
}
大元のクラスは下記です。AddEntity
よりも追加と更新を適えたUpsertEntity
を使っています。
public async Task<ReceiptModel?> UpsertReceipt(ReceiptModel receipt)
{
// Create Table.
var tableItem = CreateTable("ReceiptByStores");
// Get Table Client.
var tableClient = GetTableClient("ReceiptByStores");
// Insert.
var result = await tableClient.UpsertEntityAsync(receipt);
if (result.IsError)
{
// If error, I ll return null.
return null;
}
// Return receipt data that was inserted.
return receipt;
}
サンプルコード
MSからのサンプルはこちらにありますのでご参照ください。
メンバー募集中
一緒に開発するメンバー募集しています。副業でもOK(むしろ歓迎)、フルリモートです。