Cosmos SQL DAO (Data Access Object)











up vote
0
down vote

favorite












In my IoT project, I have cosmos DB to store telemetric and other business data.



I'm implementing DAO pattern first time, looking for better and reusable code suggestion.



DAO & Repository pattern solve same problem, I don't have any Entity (which directly map with cosmos DB collection), Single Cosmos DB collection storing multiple type of data that is why I implemented DAO pattern.



BaseDAO



public abstract class BaseDAO : IBaseDAO
{
public readonly DocumentClient client;

protected BaseDAO(IAppConfiguration appConfiguration)
{
this.client = new DocumentClient(appConfiguration.DatabaseEndPoint, appConfiguration.DatabaseKey,
new ConnectionPolicy
{
//ConnectionMode.Direct is fastest, but not recommended in consumption plan
ConnectionMode = ConnectionMode.Direct,
ConnectionProtocol = Protocol.Tcp,
// Customize retry options for Throttled requests
RetryOptions = new RetryOptions()
{
MaxRetryAttemptsOnThrottledRequests = 10,
MaxRetryWaitTimeInSeconds = 30
}
});
}

/// <summary>
/// Create Document in Database
/// </summary>
/// <param name="databaseId">database name</param>
/// <param name="collectionId">collection name</param>
/// <param name="document">document object</param>
/// <returns></returns>
public virtual async Task<string> CreateAsync(string databaseId, string collectionId, JObject document)
{
Document response = await this.client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), document);
return response.Id;
}

/// <summary>
/// Delete document from database
/// </summary>
/// <param name="databaseId">database name</param>
/// <param name="collectionId">collection name</param>
/// <param name="id">document unique id</param>
/// <returns></returns>
public virtual async Task<bool> DeleteAsync(string databaseId, string collectionId, string id)
{
await this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id));
return true;
}

/// <summary>
/// Delete document from database
/// </summary>
/// <param name="databaseId">database name</param>
/// <param name="collectionId">collection name</param>
/// <param name="id">document unique id</param>
/// /// <param name="partitionKey"> document Partition key</param>
/// <returns></returns>
public virtual async Task<bool> DeleteWithPartitionKeyAsync(string databaseId, string collectionId, string id, string partitionKey)
{
await this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id), new RequestOptions { PartitionKey = new PartitionKey(partitionKey) });
return true;
}

/// <summary>
/// Get document by id
/// </summary>
/// <param name="databaseId">database name</param>
/// <param name="collectionId">collection name</param>
/// <param name="id">document unique id</param>
/// <returns></returns>
public virtual string GetDocumentById(string databaseId, string collectionId, string id)
{
var query = new SqlQuerySpec(
"SELECT * FROM c where c.id = @id",
new SqlParameterCollection(new SqlParameter { new SqlParameter { Name = "@id", Value = id }
}));
Document document = this.client.CreateDocumentQuery<dynamic>(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), query)
.AsEnumerable().FirstOrDefault();
return Serialize(document);
}

/// <summary>
/// Get list of document with filter criteria
/// </summary>
/// <param name="databaseId">database name</param>
/// <param name="collectionId">collection name</param>
/// <param name="conditions">filter condition</param>
/// <returns></returns>
public virtual JArray GetDocuments(string databaseId, string collectionId, Dictionary<string, string> conditions)
{
if (conditions.Count == 0)
throw new ArgumentException("Condition can't be blank");

SqlParameterCollection parameters = new SqlParameterCollection();
StringBuilder whereCondition = new StringBuilder();

foreach (var condition in conditions)
{
parameters.Add(new SqlParameter { Name = $"@{condition.Key}", Value = condition.Value });
whereCondition.Append($"c.{condition.Key} = @{condition.Key} and ");
}
string where = whereCondition.ToString().Remove(whereCondition.ToString().LastIndexOf(" and "));

var query = new SqlQuerySpec(
$"SELECT * FROM c where {where}", parameters);

List<Document> documents = this.client.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), query)
.AsEnumerable().ToList();
return JArray.Parse(Serialize(documents));
}

public virtual T GetDocument<T>(string databaseId, string collectionId, Dictionary<string, string> conditions)
{
JArray documents = GetDocuments(databaseId, collectionId, conditions);
if (documents.Count > 0)
{
return JsonConvert.DeserializeObject<T>(documents.First().ToString());
}
else
{
return default(T);
}
}

/// <summary>
/// Update document in collection by id
/// </summary>
/// <param name="databaseId">database name</param>
/// <param name="collectionId">collection name</param>
/// <param name="id">document unique id</param>
/// <param name="newDocument">New document object</param>
/// <returns></returns>
public virtual async Task<bool> UpdateAsync(string databaseId, string collectionId, string id, JObject newDocument)
{
await this.client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id), newDocument);
return true;
}

public virtual string Serialize(object obj)
{
return JsonConvert.SerializeObject(obj);
}

public virtual T Deserialize<T>(string serialized)
{
return JsonConvert.DeserializeObject<T>(serialized);
}

}


MasterData Collection DAO



public class MasterDAO : BaseDAO, IMasterDAO
{
private readonly IAppConfiguration appConfiguration;

public MasterDAO(IAppConfiguration appConfiguration)
: base(appConfiguration)
{
this.appConfiguration = appConfiguration;
}

public Task<string> CreateAsync(JObject document)
{
return base.CreateAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, document);
}

public async Task<bool> DeleteAsset(string assetId, string assetType)
{
var parameters = new Dictionary<string, string>();
parameters.Add("assetid", assetId);
parameters.Add("assetType", assetType);
JArray documents = base.GetDocuments(appConfiguration.DatabaseId, AMSConstraints.MasterData, parameters);
if (documents.Count > 0)
{
string id = documents.First()["id"].ToString();
return await base.DeleteAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, id);
}
else
{
return false;
}
}

public JArray GetAssetBySerialNumber(IEnumerable<string> serialNumber)
{
//TODO: need to use parameter query (above parametrize query not working)
dynamic result = client.CreateDocumentQuery<dynamic>(
UriFactory.CreateDocumentCollectionUri(appConfiguration.DatabaseId, AMSConstraints.MasterData),
"select * FROM c where c.ApplicationName = 'Eroutes' and c.Device[0].SerialNumber IN (" + serialNumber.ListToString() + ")")
.AsEnumerable().ToList();
if (result != null && result.Count > 0)
return JArray.Parse(Serialize(result));
else
return JArray.Parse("");
}

public string GetAssetType(string make, string serialNumber)
{
var query = new SqlQuerySpec("select c.AssetType FROM c where c.ApplicationName = 'Eroutes' and c.Device[0].SerialNumber=@SerialNumber and c.Device[0].Make=@Make",
new SqlParameterCollection(new SqlParameter {
new SqlParameter { Name = "@SerialNumber", Value = serialNumber },
new SqlParameter { Name = "@Make", Value = make }
}));

dynamic result = client.CreateDocumentQuery<dynamic>(
UriFactory.CreateDocumentCollectionUri(appConfiguration.DatabaseId, AMSConstraints.MasterData), query)
.AsEnumerable().FirstOrDefault();
if (result != null)
{
var json = JObject.Parse(Serialize(result));
return json["AssetType"].ToString();
}
else
{
return string.Empty;
}
}

public async Task<bool> UpdateDocumentByAsset(string assetId, string assetType, JObject newDocument)
{
var parameters = new Dictionary<string, string>();
parameters.Add("assetid", assetId);
parameters.Add("assetType", assetType);
JArray document = base.GetDocuments(appConfiguration.DatabaseId, AMSConstraints.MasterData, parameters);
string id = document[0]["id"].ToString();
return await base.UpdateAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, id, newDocument);
}
}









share|improve this question




























    up vote
    0
    down vote

    favorite












    In my IoT project, I have cosmos DB to store telemetric and other business data.



    I'm implementing DAO pattern first time, looking for better and reusable code suggestion.



    DAO & Repository pattern solve same problem, I don't have any Entity (which directly map with cosmos DB collection), Single Cosmos DB collection storing multiple type of data that is why I implemented DAO pattern.



    BaseDAO



    public abstract class BaseDAO : IBaseDAO
    {
    public readonly DocumentClient client;

    protected BaseDAO(IAppConfiguration appConfiguration)
    {
    this.client = new DocumentClient(appConfiguration.DatabaseEndPoint, appConfiguration.DatabaseKey,
    new ConnectionPolicy
    {
    //ConnectionMode.Direct is fastest, but not recommended in consumption plan
    ConnectionMode = ConnectionMode.Direct,
    ConnectionProtocol = Protocol.Tcp,
    // Customize retry options for Throttled requests
    RetryOptions = new RetryOptions()
    {
    MaxRetryAttemptsOnThrottledRequests = 10,
    MaxRetryWaitTimeInSeconds = 30
    }
    });
    }

    /// <summary>
    /// Create Document in Database
    /// </summary>
    /// <param name="databaseId">database name</param>
    /// <param name="collectionId">collection name</param>
    /// <param name="document">document object</param>
    /// <returns></returns>
    public virtual async Task<string> CreateAsync(string databaseId, string collectionId, JObject document)
    {
    Document response = await this.client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), document);
    return response.Id;
    }

    /// <summary>
    /// Delete document from database
    /// </summary>
    /// <param name="databaseId">database name</param>
    /// <param name="collectionId">collection name</param>
    /// <param name="id">document unique id</param>
    /// <returns></returns>
    public virtual async Task<bool> DeleteAsync(string databaseId, string collectionId, string id)
    {
    await this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id));
    return true;
    }

    /// <summary>
    /// Delete document from database
    /// </summary>
    /// <param name="databaseId">database name</param>
    /// <param name="collectionId">collection name</param>
    /// <param name="id">document unique id</param>
    /// /// <param name="partitionKey"> document Partition key</param>
    /// <returns></returns>
    public virtual async Task<bool> DeleteWithPartitionKeyAsync(string databaseId, string collectionId, string id, string partitionKey)
    {
    await this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id), new RequestOptions { PartitionKey = new PartitionKey(partitionKey) });
    return true;
    }

    /// <summary>
    /// Get document by id
    /// </summary>
    /// <param name="databaseId">database name</param>
    /// <param name="collectionId">collection name</param>
    /// <param name="id">document unique id</param>
    /// <returns></returns>
    public virtual string GetDocumentById(string databaseId, string collectionId, string id)
    {
    var query = new SqlQuerySpec(
    "SELECT * FROM c where c.id = @id",
    new SqlParameterCollection(new SqlParameter { new SqlParameter { Name = "@id", Value = id }
    }));
    Document document = this.client.CreateDocumentQuery<dynamic>(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), query)
    .AsEnumerable().FirstOrDefault();
    return Serialize(document);
    }

    /// <summary>
    /// Get list of document with filter criteria
    /// </summary>
    /// <param name="databaseId">database name</param>
    /// <param name="collectionId">collection name</param>
    /// <param name="conditions">filter condition</param>
    /// <returns></returns>
    public virtual JArray GetDocuments(string databaseId, string collectionId, Dictionary<string, string> conditions)
    {
    if (conditions.Count == 0)
    throw new ArgumentException("Condition can't be blank");

    SqlParameterCollection parameters = new SqlParameterCollection();
    StringBuilder whereCondition = new StringBuilder();

    foreach (var condition in conditions)
    {
    parameters.Add(new SqlParameter { Name = $"@{condition.Key}", Value = condition.Value });
    whereCondition.Append($"c.{condition.Key} = @{condition.Key} and ");
    }
    string where = whereCondition.ToString().Remove(whereCondition.ToString().LastIndexOf(" and "));

    var query = new SqlQuerySpec(
    $"SELECT * FROM c where {where}", parameters);

    List<Document> documents = this.client.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), query)
    .AsEnumerable().ToList();
    return JArray.Parse(Serialize(documents));
    }

    public virtual T GetDocument<T>(string databaseId, string collectionId, Dictionary<string, string> conditions)
    {
    JArray documents = GetDocuments(databaseId, collectionId, conditions);
    if (documents.Count > 0)
    {
    return JsonConvert.DeserializeObject<T>(documents.First().ToString());
    }
    else
    {
    return default(T);
    }
    }

    /// <summary>
    /// Update document in collection by id
    /// </summary>
    /// <param name="databaseId">database name</param>
    /// <param name="collectionId">collection name</param>
    /// <param name="id">document unique id</param>
    /// <param name="newDocument">New document object</param>
    /// <returns></returns>
    public virtual async Task<bool> UpdateAsync(string databaseId, string collectionId, string id, JObject newDocument)
    {
    await this.client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id), newDocument);
    return true;
    }

    public virtual string Serialize(object obj)
    {
    return JsonConvert.SerializeObject(obj);
    }

    public virtual T Deserialize<T>(string serialized)
    {
    return JsonConvert.DeserializeObject<T>(serialized);
    }

    }


    MasterData Collection DAO



    public class MasterDAO : BaseDAO, IMasterDAO
    {
    private readonly IAppConfiguration appConfiguration;

    public MasterDAO(IAppConfiguration appConfiguration)
    : base(appConfiguration)
    {
    this.appConfiguration = appConfiguration;
    }

    public Task<string> CreateAsync(JObject document)
    {
    return base.CreateAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, document);
    }

    public async Task<bool> DeleteAsset(string assetId, string assetType)
    {
    var parameters = new Dictionary<string, string>();
    parameters.Add("assetid", assetId);
    parameters.Add("assetType", assetType);
    JArray documents = base.GetDocuments(appConfiguration.DatabaseId, AMSConstraints.MasterData, parameters);
    if (documents.Count > 0)
    {
    string id = documents.First()["id"].ToString();
    return await base.DeleteAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, id);
    }
    else
    {
    return false;
    }
    }

    public JArray GetAssetBySerialNumber(IEnumerable<string> serialNumber)
    {
    //TODO: need to use parameter query (above parametrize query not working)
    dynamic result = client.CreateDocumentQuery<dynamic>(
    UriFactory.CreateDocumentCollectionUri(appConfiguration.DatabaseId, AMSConstraints.MasterData),
    "select * FROM c where c.ApplicationName = 'Eroutes' and c.Device[0].SerialNumber IN (" + serialNumber.ListToString() + ")")
    .AsEnumerable().ToList();
    if (result != null && result.Count > 0)
    return JArray.Parse(Serialize(result));
    else
    return JArray.Parse("");
    }

    public string GetAssetType(string make, string serialNumber)
    {
    var query = new SqlQuerySpec("select c.AssetType FROM c where c.ApplicationName = 'Eroutes' and c.Device[0].SerialNumber=@SerialNumber and c.Device[0].Make=@Make",
    new SqlParameterCollection(new SqlParameter {
    new SqlParameter { Name = "@SerialNumber", Value = serialNumber },
    new SqlParameter { Name = "@Make", Value = make }
    }));

    dynamic result = client.CreateDocumentQuery<dynamic>(
    UriFactory.CreateDocumentCollectionUri(appConfiguration.DatabaseId, AMSConstraints.MasterData), query)
    .AsEnumerable().FirstOrDefault();
    if (result != null)
    {
    var json = JObject.Parse(Serialize(result));
    return json["AssetType"].ToString();
    }
    else
    {
    return string.Empty;
    }
    }

    public async Task<bool> UpdateDocumentByAsset(string assetId, string assetType, JObject newDocument)
    {
    var parameters = new Dictionary<string, string>();
    parameters.Add("assetid", assetId);
    parameters.Add("assetType", assetType);
    JArray document = base.GetDocuments(appConfiguration.DatabaseId, AMSConstraints.MasterData, parameters);
    string id = document[0]["id"].ToString();
    return await base.UpdateAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, id, newDocument);
    }
    }









    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      In my IoT project, I have cosmos DB to store telemetric and other business data.



      I'm implementing DAO pattern first time, looking for better and reusable code suggestion.



      DAO & Repository pattern solve same problem, I don't have any Entity (which directly map with cosmos DB collection), Single Cosmos DB collection storing multiple type of data that is why I implemented DAO pattern.



      BaseDAO



      public abstract class BaseDAO : IBaseDAO
      {
      public readonly DocumentClient client;

      protected BaseDAO(IAppConfiguration appConfiguration)
      {
      this.client = new DocumentClient(appConfiguration.DatabaseEndPoint, appConfiguration.DatabaseKey,
      new ConnectionPolicy
      {
      //ConnectionMode.Direct is fastest, but not recommended in consumption plan
      ConnectionMode = ConnectionMode.Direct,
      ConnectionProtocol = Protocol.Tcp,
      // Customize retry options for Throttled requests
      RetryOptions = new RetryOptions()
      {
      MaxRetryAttemptsOnThrottledRequests = 10,
      MaxRetryWaitTimeInSeconds = 30
      }
      });
      }

      /// <summary>
      /// Create Document in Database
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="document">document object</param>
      /// <returns></returns>
      public virtual async Task<string> CreateAsync(string databaseId, string collectionId, JObject document)
      {
      Document response = await this.client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), document);
      return response.Id;
      }

      /// <summary>
      /// Delete document from database
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="id">document unique id</param>
      /// <returns></returns>
      public virtual async Task<bool> DeleteAsync(string databaseId, string collectionId, string id)
      {
      await this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id));
      return true;
      }

      /// <summary>
      /// Delete document from database
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="id">document unique id</param>
      /// /// <param name="partitionKey"> document Partition key</param>
      /// <returns></returns>
      public virtual async Task<bool> DeleteWithPartitionKeyAsync(string databaseId, string collectionId, string id, string partitionKey)
      {
      await this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id), new RequestOptions { PartitionKey = new PartitionKey(partitionKey) });
      return true;
      }

      /// <summary>
      /// Get document by id
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="id">document unique id</param>
      /// <returns></returns>
      public virtual string GetDocumentById(string databaseId, string collectionId, string id)
      {
      var query = new SqlQuerySpec(
      "SELECT * FROM c where c.id = @id",
      new SqlParameterCollection(new SqlParameter { new SqlParameter { Name = "@id", Value = id }
      }));
      Document document = this.client.CreateDocumentQuery<dynamic>(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), query)
      .AsEnumerable().FirstOrDefault();
      return Serialize(document);
      }

      /// <summary>
      /// Get list of document with filter criteria
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="conditions">filter condition</param>
      /// <returns></returns>
      public virtual JArray GetDocuments(string databaseId, string collectionId, Dictionary<string, string> conditions)
      {
      if (conditions.Count == 0)
      throw new ArgumentException("Condition can't be blank");

      SqlParameterCollection parameters = new SqlParameterCollection();
      StringBuilder whereCondition = new StringBuilder();

      foreach (var condition in conditions)
      {
      parameters.Add(new SqlParameter { Name = $"@{condition.Key}", Value = condition.Value });
      whereCondition.Append($"c.{condition.Key} = @{condition.Key} and ");
      }
      string where = whereCondition.ToString().Remove(whereCondition.ToString().LastIndexOf(" and "));

      var query = new SqlQuerySpec(
      $"SELECT * FROM c where {where}", parameters);

      List<Document> documents = this.client.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), query)
      .AsEnumerable().ToList();
      return JArray.Parse(Serialize(documents));
      }

      public virtual T GetDocument<T>(string databaseId, string collectionId, Dictionary<string, string> conditions)
      {
      JArray documents = GetDocuments(databaseId, collectionId, conditions);
      if (documents.Count > 0)
      {
      return JsonConvert.DeserializeObject<T>(documents.First().ToString());
      }
      else
      {
      return default(T);
      }
      }

      /// <summary>
      /// Update document in collection by id
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="id">document unique id</param>
      /// <param name="newDocument">New document object</param>
      /// <returns></returns>
      public virtual async Task<bool> UpdateAsync(string databaseId, string collectionId, string id, JObject newDocument)
      {
      await this.client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id), newDocument);
      return true;
      }

      public virtual string Serialize(object obj)
      {
      return JsonConvert.SerializeObject(obj);
      }

      public virtual T Deserialize<T>(string serialized)
      {
      return JsonConvert.DeserializeObject<T>(serialized);
      }

      }


      MasterData Collection DAO



      public class MasterDAO : BaseDAO, IMasterDAO
      {
      private readonly IAppConfiguration appConfiguration;

      public MasterDAO(IAppConfiguration appConfiguration)
      : base(appConfiguration)
      {
      this.appConfiguration = appConfiguration;
      }

      public Task<string> CreateAsync(JObject document)
      {
      return base.CreateAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, document);
      }

      public async Task<bool> DeleteAsset(string assetId, string assetType)
      {
      var parameters = new Dictionary<string, string>();
      parameters.Add("assetid", assetId);
      parameters.Add("assetType", assetType);
      JArray documents = base.GetDocuments(appConfiguration.DatabaseId, AMSConstraints.MasterData, parameters);
      if (documents.Count > 0)
      {
      string id = documents.First()["id"].ToString();
      return await base.DeleteAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, id);
      }
      else
      {
      return false;
      }
      }

      public JArray GetAssetBySerialNumber(IEnumerable<string> serialNumber)
      {
      //TODO: need to use parameter query (above parametrize query not working)
      dynamic result = client.CreateDocumentQuery<dynamic>(
      UriFactory.CreateDocumentCollectionUri(appConfiguration.DatabaseId, AMSConstraints.MasterData),
      "select * FROM c where c.ApplicationName = 'Eroutes' and c.Device[0].SerialNumber IN (" + serialNumber.ListToString() + ")")
      .AsEnumerable().ToList();
      if (result != null && result.Count > 0)
      return JArray.Parse(Serialize(result));
      else
      return JArray.Parse("");
      }

      public string GetAssetType(string make, string serialNumber)
      {
      var query = new SqlQuerySpec("select c.AssetType FROM c where c.ApplicationName = 'Eroutes' and c.Device[0].SerialNumber=@SerialNumber and c.Device[0].Make=@Make",
      new SqlParameterCollection(new SqlParameter {
      new SqlParameter { Name = "@SerialNumber", Value = serialNumber },
      new SqlParameter { Name = "@Make", Value = make }
      }));

      dynamic result = client.CreateDocumentQuery<dynamic>(
      UriFactory.CreateDocumentCollectionUri(appConfiguration.DatabaseId, AMSConstraints.MasterData), query)
      .AsEnumerable().FirstOrDefault();
      if (result != null)
      {
      var json = JObject.Parse(Serialize(result));
      return json["AssetType"].ToString();
      }
      else
      {
      return string.Empty;
      }
      }

      public async Task<bool> UpdateDocumentByAsset(string assetId, string assetType, JObject newDocument)
      {
      var parameters = new Dictionary<string, string>();
      parameters.Add("assetid", assetId);
      parameters.Add("assetType", assetType);
      JArray document = base.GetDocuments(appConfiguration.DatabaseId, AMSConstraints.MasterData, parameters);
      string id = document[0]["id"].ToString();
      return await base.UpdateAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, id, newDocument);
      }
      }









      share|improve this question















      In my IoT project, I have cosmos DB to store telemetric and other business data.



      I'm implementing DAO pattern first time, looking for better and reusable code suggestion.



      DAO & Repository pattern solve same problem, I don't have any Entity (which directly map with cosmos DB collection), Single Cosmos DB collection storing multiple type of data that is why I implemented DAO pattern.



      BaseDAO



      public abstract class BaseDAO : IBaseDAO
      {
      public readonly DocumentClient client;

      protected BaseDAO(IAppConfiguration appConfiguration)
      {
      this.client = new DocumentClient(appConfiguration.DatabaseEndPoint, appConfiguration.DatabaseKey,
      new ConnectionPolicy
      {
      //ConnectionMode.Direct is fastest, but not recommended in consumption plan
      ConnectionMode = ConnectionMode.Direct,
      ConnectionProtocol = Protocol.Tcp,
      // Customize retry options for Throttled requests
      RetryOptions = new RetryOptions()
      {
      MaxRetryAttemptsOnThrottledRequests = 10,
      MaxRetryWaitTimeInSeconds = 30
      }
      });
      }

      /// <summary>
      /// Create Document in Database
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="document">document object</param>
      /// <returns></returns>
      public virtual async Task<string> CreateAsync(string databaseId, string collectionId, JObject document)
      {
      Document response = await this.client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), document);
      return response.Id;
      }

      /// <summary>
      /// Delete document from database
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="id">document unique id</param>
      /// <returns></returns>
      public virtual async Task<bool> DeleteAsync(string databaseId, string collectionId, string id)
      {
      await this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id));
      return true;
      }

      /// <summary>
      /// Delete document from database
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="id">document unique id</param>
      /// /// <param name="partitionKey"> document Partition key</param>
      /// <returns></returns>
      public virtual async Task<bool> DeleteWithPartitionKeyAsync(string databaseId, string collectionId, string id, string partitionKey)
      {
      await this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id), new RequestOptions { PartitionKey = new PartitionKey(partitionKey) });
      return true;
      }

      /// <summary>
      /// Get document by id
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="id">document unique id</param>
      /// <returns></returns>
      public virtual string GetDocumentById(string databaseId, string collectionId, string id)
      {
      var query = new SqlQuerySpec(
      "SELECT * FROM c where c.id = @id",
      new SqlParameterCollection(new SqlParameter { new SqlParameter { Name = "@id", Value = id }
      }));
      Document document = this.client.CreateDocumentQuery<dynamic>(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), query)
      .AsEnumerable().FirstOrDefault();
      return Serialize(document);
      }

      /// <summary>
      /// Get list of document with filter criteria
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="conditions">filter condition</param>
      /// <returns></returns>
      public virtual JArray GetDocuments(string databaseId, string collectionId, Dictionary<string, string> conditions)
      {
      if (conditions.Count == 0)
      throw new ArgumentException("Condition can't be blank");

      SqlParameterCollection parameters = new SqlParameterCollection();
      StringBuilder whereCondition = new StringBuilder();

      foreach (var condition in conditions)
      {
      parameters.Add(new SqlParameter { Name = $"@{condition.Key}", Value = condition.Value });
      whereCondition.Append($"c.{condition.Key} = @{condition.Key} and ");
      }
      string where = whereCondition.ToString().Remove(whereCondition.ToString().LastIndexOf(" and "));

      var query = new SqlQuerySpec(
      $"SELECT * FROM c where {where}", parameters);

      List<Document> documents = this.client.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(databaseId, collectionId), query)
      .AsEnumerable().ToList();
      return JArray.Parse(Serialize(documents));
      }

      public virtual T GetDocument<T>(string databaseId, string collectionId, Dictionary<string, string> conditions)
      {
      JArray documents = GetDocuments(databaseId, collectionId, conditions);
      if (documents.Count > 0)
      {
      return JsonConvert.DeserializeObject<T>(documents.First().ToString());
      }
      else
      {
      return default(T);
      }
      }

      /// <summary>
      /// Update document in collection by id
      /// </summary>
      /// <param name="databaseId">database name</param>
      /// <param name="collectionId">collection name</param>
      /// <param name="id">document unique id</param>
      /// <param name="newDocument">New document object</param>
      /// <returns></returns>
      public virtual async Task<bool> UpdateAsync(string databaseId, string collectionId, string id, JObject newDocument)
      {
      await this.client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(databaseId, collectionId, id), newDocument);
      return true;
      }

      public virtual string Serialize(object obj)
      {
      return JsonConvert.SerializeObject(obj);
      }

      public virtual T Deserialize<T>(string serialized)
      {
      return JsonConvert.DeserializeObject<T>(serialized);
      }

      }


      MasterData Collection DAO



      public class MasterDAO : BaseDAO, IMasterDAO
      {
      private readonly IAppConfiguration appConfiguration;

      public MasterDAO(IAppConfiguration appConfiguration)
      : base(appConfiguration)
      {
      this.appConfiguration = appConfiguration;
      }

      public Task<string> CreateAsync(JObject document)
      {
      return base.CreateAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, document);
      }

      public async Task<bool> DeleteAsset(string assetId, string assetType)
      {
      var parameters = new Dictionary<string, string>();
      parameters.Add("assetid", assetId);
      parameters.Add("assetType", assetType);
      JArray documents = base.GetDocuments(appConfiguration.DatabaseId, AMSConstraints.MasterData, parameters);
      if (documents.Count > 0)
      {
      string id = documents.First()["id"].ToString();
      return await base.DeleteAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, id);
      }
      else
      {
      return false;
      }
      }

      public JArray GetAssetBySerialNumber(IEnumerable<string> serialNumber)
      {
      //TODO: need to use parameter query (above parametrize query not working)
      dynamic result = client.CreateDocumentQuery<dynamic>(
      UriFactory.CreateDocumentCollectionUri(appConfiguration.DatabaseId, AMSConstraints.MasterData),
      "select * FROM c where c.ApplicationName = 'Eroutes' and c.Device[0].SerialNumber IN (" + serialNumber.ListToString() + ")")
      .AsEnumerable().ToList();
      if (result != null && result.Count > 0)
      return JArray.Parse(Serialize(result));
      else
      return JArray.Parse("");
      }

      public string GetAssetType(string make, string serialNumber)
      {
      var query = new SqlQuerySpec("select c.AssetType FROM c where c.ApplicationName = 'Eroutes' and c.Device[0].SerialNumber=@SerialNumber and c.Device[0].Make=@Make",
      new SqlParameterCollection(new SqlParameter {
      new SqlParameter { Name = "@SerialNumber", Value = serialNumber },
      new SqlParameter { Name = "@Make", Value = make }
      }));

      dynamic result = client.CreateDocumentQuery<dynamic>(
      UriFactory.CreateDocumentCollectionUri(appConfiguration.DatabaseId, AMSConstraints.MasterData), query)
      .AsEnumerable().FirstOrDefault();
      if (result != null)
      {
      var json = JObject.Parse(Serialize(result));
      return json["AssetType"].ToString();
      }
      else
      {
      return string.Empty;
      }
      }

      public async Task<bool> UpdateDocumentByAsset(string assetId, string assetType, JObject newDocument)
      {
      var parameters = new Dictionary<string, string>();
      parameters.Add("assetid", assetId);
      parameters.Add("assetType", assetType);
      JArray document = base.GetDocuments(appConfiguration.DatabaseId, AMSConstraints.MasterData, parameters);
      string id = document[0]["id"].ToString();
      return await base.UpdateAsync(appConfiguration.DatabaseId, AMSConstraints.MasterData, id, newDocument);
      }
      }






      c# azure-cosmosdb






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 1 min ago









      t3chb0t

      33.6k744108




      33.6k744108










      asked 41 mins ago









      Pankaj Rawat

      1146




      1146



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208211%2fcosmos-sql-dao-data-access-object%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208211%2fcosmos-sql-dao-data-access-object%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          404 Error Contact Form 7 ajax form submitting

          How to know if a Active Directory user can login interactively

          TypeError: fit_transform() missing 1 required positional argument: 'X'