はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

Windows Azrue Mobile Services SDKでnull値更新を行う。

Windows Azure Mobiel Servicesは、REST APIで利用することができるが、Windows 8 / Windows Phone 8 / iOS / Android / Xamarin / JavaScriptにはSDKが用意されていてREST / JSONを意識しなくてもよいように考慮されています。

 

例えば、WindowsストアアプリでInfoテーブルから参照や更新を行うときには次のようなコードになります。

public class Info
{
    public long Id { get; set; }
    public string LocationName { get; set; }
    public string FullAddress { get; set; }
    public float Latitude { get; set; }
    public float Longitude { get; set; }
    public int? LocationAltitude { get; set; }
}

public ObservableCollection Items = new ObservableCollection();

using (MobileServiceClient mobileService = new MobileServiceClient(Settings.AppUrl, Settings.AppKey))
{
    IMobileServiceTable qTable = mobileService.GetTable();
    var items = await qTable.ReadAsync();

    this.Items.Clear();
    foreach (var item in items)
    {
        this.Items.Add(item);
    }
}

using (MobileServiceClient mobileService = new MobileServiceClient(Settings.AppUrl, Settings.AppKey))
{

    IMobileServiceTable qTable = mobileService.GetTable();
    await qTable.UpdateAsync(this.Item);
}

この方式により、コード側ではItemsコレクションの要素を意識すればよいレベルにまで単純化できます。

 

更にAzure SQL Serverにある既存テーブルへの更新などについてもカスタムAPIをAzure Mobile Services側に定義しておいて、クライアント側では次のようにInvokeApiAsyncメソッドで実現可能です。

await mobileService.InvokeApiAsync<IEnumerable>(
    "CustomInfo",
    System.Net.Http.HttpMethod.Post,
    paramList);   

しかしここで問題が発生します。


最後のパラメタparamListに更新項目と更新値をIDictonary<string, string>形式で指定するのですが、ここで指定された値はSDKの中でURLパラメタとして展開されるためnull値を指定しようとするとSDKの中で実行時エラーになってしまうのです。

更新値をJSON形式にできればnull値も設定できるのですが、SDKのソースを読んでみてもカスタムAPIの更新系でそれを実現するのはちょっと難しそうな感じでした。

 

そこで思いついた解決方法がInvokeApiAsyncメソッドではなくUpdateAsyncメソッドでレコードを更新する方法です。

using (MobileServiceClient mobileService = new MobileServiceClient(Settings.AppUrl, Settings.AppKey))
{
    IMobileServiceTable qTable = mobileService.GetTable();
    var paramList = SetParameters();
    await qTable.UpdateAsync(paramList);
}

private Newtonsoft.Json.Linq.JObject SetParameters()
{
    Newtonsoft.Json.Linq.JObject paramList = new Newtonsoft.Json.Linq.JObject()
    {
        {"id", this.Item.Id.ToString()},
        {"LocationName", this.Item.LocationName},
        {"FullAddress", this.Item.FullAddress},
        {"Latitude", this.Item.Latitude},
        {"Longitude", this.Item.Longitude},
        {"LocationAltitude", this.Item.LocationAltitude}
    };
    return paramList;
}    

ここで注意しないといけないのは「id」についてはすべて小文字で「id」と指定しなければならない点です。
これは、Azure Mobile Servicesでテーブルを作成した時に「id」と初期定義されているからです。

 

このクライアント側のコードでは、Azure Mobile ServicesにあるInfoテーブルが更新されることになりますが、Windows Azure SQL Serverに別定義したテーブルを更新することも可能です。

その方法とは、Azure Mobile ServicesのInfoテーブルの更新スクリプトでInfoテーブルではなく、その別テーブルへの更新を記述してしまう事です。

function update(item, user, request) {
    console.log(item.id);
    var sql = 'UPDATE CustomInfo ' +
                 'SET LocationName = ? ' +
                   ', FullAddress = ? ' +
                   ', GeoCoordinate = geography::Point(?, ?, 4326) ' +
                   ', LocationAltitude = ? ' +
                   ', DateOfUpdatingInformation = ? ' +
                   ', __updateAt = ? ' +
               'WHERE Id = ?';
    var params = [];
    params.push(item.LocationName);
    params.push(item.FullAddress);
    params.push(item.Latitude);
    params.push(item.Longitude);
    params.push(item.LocationAltitude);
    params.push(new Date());
    params.push(new Date());
    params.push(item.id);
    mssql.query(sql, params,
            {
                success: function(results)
                {
                    request.respond(statusCodes.OK, results);
                },
                error : function()
                {
                    request.respond(statusCodes.INTERNAL_SERVER_ERROR);
                }
            }
    );
}

これで、Azure SQL Serverに直接定義しているCustomInfoテーブルを更新することができます。もちろん、JSONでサーバーまでわたっていくのでnull値での更新も問題ありません。