parsing dynamo db queryresponse to object - amazon-dynamodb

I'm using DynamoDB to query a table with the following commands
QueryRequest request = new QueryRequest
{
TableName = "Events",
ExclusiveStartKey = startKey,
KeyConditions = keyConditions,
IndexName = "Title-index" // Specify the index to query against
};
// Issue request
QueryResponse result = client.Query(request);
The ExclusiveStartKey and Keyconditions are predefined
The issue is that the QueryResult result variable is not parsed to my native object, when I use the DynamoDB.Context you cast the method with the expected type, but in this case I need to parse the QueryResult...
Is there any other way to do this?
Or should I parse the object?

I ended up using something like:
using System.Linq;
...
// Issue request
QueryResponse result = AmazonDynamoDBClient.Query(request);
var items = result.Items.FirstOrDefault();
var doc = Document.FromAttributeMap(items);
var myModel = DynamoDBContext.FromDocument<MyModelType>(doc);

What you want is some sort of ORM - a nice read is Using Amazon DynamoDB Object Persistence Framework. Also check out the API reference that also shows samples

Take a look at the examples from Querying Tables Using the AWS SDK for .NET Low-Level API documentation
In your handling method
var response = client.Query(request);
var result = response.QueryResult;
foreach (Dictionary<string, AttributeValue> item in response.QueryResult.Items)
{
// Process the result.
PrintItem(item);
}
PrintItem implementation
private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
{
foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
{
string attributeName = kvp.Key;
AttributeValue value = kvp.Value;
Console.WriteLine(
attributeName + " " +
(value.S == null ? "" : "S=[" + value.S + "]") +
(value.N == null ? "" : "N=[" + value.N + "]") +
(value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
(value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
);
}
Console.WriteLine("************************************************");
}

I was stuck on the same issue, and found that by using Table.Query with a QueryOperationConfig I could specify the index that I wanted to use. Because the Document object returned from this query has a "ToJson()" method on it, I was able to convert the results of the query to Json, and then use Json.Net to Deserialize it back into my object which worked flawlessly for my totally flat object.
var queryFilter = new QueryFilter(indexedColumnName, QueryOperator.Equal, targetValue);
Table table = Table.LoadTable(client, Configuration.Instance.DynamoTable);
var search = table.Query(new QueryOperationConfig { IndexName = indexName, Filter = queryFilter });
List<MyObject> objects = new List<MyObject>();
List<Document> documentSet = new List<Document>();
do
{
documentSet = search.GetNextSetAsync().Result;
foreach (var document in documentSet)
{
var record = JsonConvert.DeserializeObject<MyObject>(document.ToJson());
objects .Add(record);
}
} while (!search.IsDone);
Hope it helps you out!

Related

ASP.NET Entity Framework request SQL

I need to write this SQL statement in Entity Framework:
SELECT
SALARIE.MATRICULE, LIEU, UO, UO_RATTACHEMENT,
PHOTO.PHOTO, SALARIE.NOM, SALARIE.PRENOM
FROM
SALARIE, UNITE_ORG, PHOTO
WHERE
SALARIE.LIEU = UNITE_ORG.UO
I use this method for reading my data :
public JsonResult Read()
{
var nodes = entities.UNITE_ORG.Select(p => new NodeModel { id = p.UO, pid = p.UO_RATTACHEMENT, poste = p.POSTE, img=p.LIB_COMPLET, Fullname=p.RESPONSABLE });
return Json(new { nodes = nodes }, JsonRequestBehavior.AllowGet);
}
I need to change this declaration of nodes.
Thank you
I believe that the equivalent Entity Framework would be the following:
var result = (from s in context.SALARIE
from u in context.UNITE_ORG
from p in context.PHOTO
where s.LIEU == u.UO
select new {
MATRICULE = s.MATRICULE,
LIEU = s.LIEU,
UO = u.UO,
UO_RATTACHEMENT = UO_RATTACHEMENT, // I don't know where this is coming from
PHOTO = p.PHOTO,
NOM = s.NOM,
PRENOM = s.PRENOM
}
);
However, this is just a guess from the information you have giving.
Also, like I have stated in my comment, I really think you should stop using the syntax for cross joins that you are doing (the , seperated syntax)

Dynamically ignore attributes when saving items with .NET AWS SDK Object Persistence Model

Is it possible to dynamically ignore some properties when saving items with the .NET Object Persistence Model?
I don't want to decorate my class properties with DynamoDBIgnore because sometimes I do want to save the changes being made in those.
I have tried to set IgnoreNullValues to true however this did not work when saving items with a batch.
Code is as follows:
using (var context = new DynamoDBContext(awsClient, _dynamoDbContextConfig))
{
var batch = context.CreateBatchWrite<T>(
new DynamoDBOperationConfig {SkipVersionCheck = true, IgnoreNullValues = true});
batch.AddPutItems(items);
await context.ExecuteBatchWriteAsync(new BatchWrite[] {batch});
}
Shall I use the lower-level API for achieving this?
The lower level API (exposed through IAmazonDynamoDB / AmazonDynamoDbClient) is the only way I have found till now of updating individual properties of an existing DynamoDB document.
An example of this would be :
var updateItemRequest = new UpdateItemRequest
{
TableName = "search_log_table",
Key = new Dictionary<string, AttributeValue>
{
{"PK", new AttributeValue("pk_value")},
{"SK", new AttributeValue("sk_value")}
},
UpdateExpression = $"SET SearchCount = if_not_exists(SearchCount, :start) + :inc",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{":start", new AttributeValue {N = "0"}},
{":inc", new AttributeValue {N = "1"}}
},
ReturnValues = "UPDATED_NEW"
};
// _client is an instance of IAmazonDynamoDB
return _client.UpdateItemAsync(updateItemRequest);
This inserts a new record with PK = "pk_value", SK = "sk_value" if one does not exist.
The statement UpdateExpression = $"SET SearchCount = if_not_exists(SearchCount, :start) + :inc sets the SearchCount to 1 the first time, and increments the property by 1 on every subsequent invocation

DeExpress MVC 17.1 How populate TokenBox from a database

I want populate a TokenBox from a database using the property tokenBoxSettings.Properties.DataSource
TokenBoxView.cshtml
groupSettings.Items.Add(
formLayoutSettings.Items.Add(i =>
{
i.FieldName = "email";
i.Caption = "Email";
i.NestedExtensionType = FormLayoutNestedExtensionItemType.TokenBox;
TokenBoxSettings tokenBoxSettings = (TokenBoxSettings) i.NestedExtensionSettings;
tokenBoxSettings.Width = 350;
//data binding
tokenBoxSettings.Properties.DataSource = mainController.GetMails();
tokenBoxSettings.Properties.TextField = "email_empresarial";
tokenBoxSettings.Properties.ValueField = "email_empresarial";
tokenBoxSettings.Properties.IncrementalFilteringMode = IncrementalFilteringMode.Contains;
tokenBoxSettings.Properties.ValueSeparator = ';';
})
);
TokenBoxController.cs
//mainController
//I created a dictionary based on the result of select
public Dictionary<string, string> GetMails()
{
var email = db.usuario.ToList().Select(e => new { e.email_empresarial });
var emails = new Dictionary<string, string>();
foreach (var mail in email)
{
correos.Add(mail.ToString(), mail.ToString());
}
return emails;
}
But it shows me the "object explicitly", I only need the value, for example kenneth or manuel
tokenBox list
What am I doing wrong? or with what other approach I can do?
You are specifying same email_empresarial field name for both tokenBoxSettings.Properties.TextField and tokenBoxSettings.Properties.ValueField.
Since you are binding your TokenBox to Dictionary, try changing settings for TextField and ValueField to reference Dictionary Key and Value, like this:
tokenBoxSettings.Properties.TextField = "Value";
tokenBoxSettings.Properties.ValueField = "Key";
Also, in your GetMail() method you have declared the var emails but in the loop you are adding items to the undeclared correos variable. Are you sure you don't have a bug here?
Another note, in the Dictionary returned by GetMails() you populate both dictionary keys and values with the same value of mail.ToString(). Are you sure you really need to use Dictionary to bind your TokenBox? If keys and values are equal you may try going with plain List<string>.

How to pass non-optional NULL parameters to a Stored Proc using OrmLite

I'm using OrmLite against an existing SQL Server database that has published stored procedures for access. One of these SPs takes 3 int parameters, but expects that one or another will be null. However, none of the parameters are declared optional.
Here's the code I've tried:
using (IDbConnection scon = myFactory.OpenDbConnection())
{
rowCount = scon.SqlScalar<int>("EXEC myProc #FileID, #FileTypeID, #POID",
new
{
FileID = req.FileId,
FileTypeID = (int?)null,
POID = req.PoId,
});
}
But this produces a SqlException: Must declare the scalar variable "#FileTypeID". Examining the SQLParameterCollection under the covers shows that only two parameters are being generated by OrmLite.
Is it possible to call this SP with a null parameter?
It's not supported with SqlScalar. When you look at the code then you can see that SqlScalar methods from class ServiceStack.OrmLite.OrmLiteReadExtensions execute SetParameters method responsible for adding parameters to query with second parameter(excludeNulls) equal true I don't know why- mythz should answer for this ;).
If you want to fix it then you have change all SqlScalar methods to invoke SetParameters with true and SetParameters method should look like following(must support DBNull.Value not null)
private static void SetParameters(this IDbCommand dbCmd, object anonType, bool excludeNulls)
{
dbCmd.Parameters.Clear();
lastQueryType = null;
if (anonType == null) return;
var pis = anonType.GetType().GetSerializableProperties();
foreach (var pi in pis)
{
var mi = pi.GetGetMethod();
if (mi == null) continue;
var value = mi.Invoke(anonType, new object[0]);
if (excludeNulls && value == null) continue;
var p = dbCmd.CreateParameter();
p.ParameterName = pi.Name;
p.DbType = OrmLiteConfig.DialectProvider.GetColumnDbType(pi.PropertyType);
p.Direction = ParameterDirection.Input;
p.Value = value ?? DBNull.Value; // I HAVE CHANGED THAT LINE ONLY
dbCmd.Parameters.Add(p);
}
}
When you change code then you can set null for parameters in the following way:
var result = db.SqlScalar<int>("EXEC DummyScalar #Times", new { Times = (int?)null });
In my opinion you can describe it as a defect on github and I can make pull request.

NameValueCollection to URL Query?

I know i can do this
var nv = HttpUtility.ParseQueryString(req.RawUrl);
But is there a way to convert this back to a url?
var newUrl = HttpUtility.Something("/page", nv);
Simply calling ToString() on the NameValueCollection will return the name value pairs in a name1=value1&name2=value2 querystring ready format. Note that NameValueCollection types don't actually support this and it's misleading to suggest this, but the behavior works here due to the internal type that's actually returned, as explained below.
Thanks to #mjwills for pointing out that the HttpUtility.ParseQueryString method actually returns an internal HttpValueCollection object rather than a regular NameValueCollection (despite the documentation specifying NameValueCollection). The HttpValueCollection automatically encodes the querystring when using ToString(), so there's no need to write a routine that loops through the collection and uses the UrlEncode method. The desired result is already returned.
With the result in hand, you can then append it to the URL and redirect:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
string url = Request.Url.AbsolutePath + "?" + nameValues.ToString();
Response.Redirect(url);
Currently the only way to use a HttpValueCollection is by using the ParseQueryString method shown above (other than reflection, of course). It looks like this won't change since the Connect issue requesting this class be made public has been closed with a status of "won't fix."
As an aside, you can call the Add, Set, and Remove methods on nameValues to modify any of the querystring items before appending it. If you're interested in that see my response to another question.
string q = String.Join("&",
nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
Make an extension method that uses a couple of loops. I prefer this solution because it's readable (no linq), doesn't require System.Web.HttpUtility, and it supports duplicate keys.
public static string ToQueryString(this NameValueCollection nvc)
{
if (nvc == null) return string.Empty;
StringBuilder sb = new StringBuilder();
foreach (string key in nvc.Keys)
{
if (string.IsNullOrWhiteSpace(key)) continue;
string[] values = nvc.GetValues(key);
if (values == null) continue;
foreach (string value in values)
{
sb.Append(sb.Length == 0 ? "?" : "&");
sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value));
}
}
return sb.ToString();
}
Example
var queryParams = new NameValueCollection()
{
{ "order_id", "0000" },
{ "item_id", "1111" },
{ "item_id", "2222" },
{ null, "skip entry with null key" },
{ "needs escaping", "special chars ? = &" },
{ "skip entry with null value", null }
};
Console.WriteLine(queryParams.ToQueryString());
Output
?order_id=0000&item_id=1111&item_id=2222&needs%20escaping=special%20chars%20%3F%20%3D%20%26
This should work without too much code:
NameValueCollection nameValues = HttpUtility.ParseQueryString(String.Empty);
nameValues.Add(Request.QueryString);
// modify nameValues if desired
var newUrl = "/page?" + nameValues;
The idea is to use HttpUtility.ParseQueryString to generate an empty collection of type HttpValueCollection. This class is a subclass of NameValueCollection that is marked as internal so that your code cannot easily create an instance of it.
The nice thing about HttpValueCollection is that the ToString method takes care of the encoding for you. By leveraging the NameValueCollection.Add(NameValueCollection) method, you can add the existing query string parameters to your newly created object without having to first convert the Request.QueryString collection into a url-encoded string, then parsing it back into a collection.
This technique can be exposed as an extension method as well:
public static string ToQueryString(this NameValueCollection nameValueCollection)
{
NameValueCollection httpValueCollection = HttpUtility.ParseQueryString(String.Empty);
httpValueCollection.Add(nameValueCollection);
return httpValueCollection.ToString();
}
Actually, you should encode the key too, not just value.
string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));
Because a NameValueCollection can have multiple values for the same key, if you are concerned with the format of the querystring (since it will be returned as comma-separated values rather than "array notation") you may consider the following.
Example
var nvc = new NameValueCollection();
nvc.Add("key1", "val1");
nvc.Add("key2", "val2");
nvc.Add("empty", null);
nvc.Add("key2", "val2b");
Turn into: key1=val1&key2[]=val2&empty&key2[]=val2b rather than key1=val1&key2=val2,val2b&empty.
Code
string qs = string.Join("&",
// "loop" the keys
nvc.AllKeys.SelectMany(k => {
// "loop" the values
var values = nvc.GetValues(k);
if(values == null) return new[]{ k };
return nvc.GetValues(k).Select( (v,i) =>
// 'gracefully' handle formatting
// when there's 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(v), i)
);
})
);
or if you don't like Linq so much...
string qs = nvc.ToQueryString(); // using...
public static class UrlExtensions {
public static string ToQueryString(this NameValueCollection nvc) {
return string.Join("&", nvc.GetUrlList());
}
public static IEnumerable<string> GetUrlList(this NameValueCollection nvc) {
foreach(var k in nvc.AllKeys) {
var values = nvc.GetValues(k);
if(values == null) { yield return k; continue; }
for(int i = 0; i < values.Length; i++) {
yield return
// 'gracefully' handle formatting
// when there's 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(values[i]), i);
}
}
}
}
As has been pointed out in comments already, with the exception of this answer most of the other answers address the scenario (Request.QueryString is an HttpValueCollection, "not" a NameValueCollection) rather than the literal question.
Update: addressed null value issue from comment.
The short answer is to use .ToString() on the NameValueCollection and combine it with the original url.
However, I'd like to point out a few things:
You cant use HttpUtility.ParseQueryString on Request.RawUrl. The ParseQueryString() method is looking for a value like this: ?var=value&var2=value2.
If you want to get a NameValueCollection of the QueryString parameters just use Request.QueryString().
var nv = Request.QueryString;
To rebuild the URL just use nv.ToString().
string url = String.Format("{0}?{1}", Request.Path, nv.ToString());
If you are trying to parse a url string instead of using the Request object use Uri and the HttpUtility.ParseQueryString method.
Uri uri = new Uri("<THE URL>");
var nv = HttpUtility.ParseQueryString(uri.Query);
string url = String.Format("{0}?{1}", uri.AbsolutePath, nv.ToString());
I always use UriBuilder to convert an url with a querystring back to a valid and properly encoded url.
var url = "http://my-link.com?foo=bar";
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("yep", "foo&bar");
uriBuilder.Query = query.ToString();
var result = uriBuilder.ToString();
// http://my-link.com:80/?foo=bar&yep=foo%26bar
In AspNet Core 2.0 you can use QueryHelpers AddQueryString method.
As #Atchitutchuk suggested, you can use QueryHelpers.AddQueryString in ASP.NET Core:
public string FormatParameters(NameValueCollection parameters)
{
var queryString = "";
foreach (var key in parameters.AllKeys)
{
foreach (var value in parameters.GetValues(key))
{
queryString = QueryHelpers.AddQueryString(queryString, key, value);
}
};
return queryString.TrimStart('?');
}
This did the trick for me:
public ActionResult SetLanguage(string language = "fr_FR")
{
Request.UrlReferrer.TryReadQueryAs(out RouteValueDictionary parameters);
parameters["language"] = language;
return RedirectToAction("Index", parameters);
}
You can use.
var ur = new Uri("/page",UriKind.Relative);
if this nv is of type string you can append to the uri first parameter.
Like
var ur2 = new Uri("/page?"+nv.ToString(),UriKind.Relative);

Resources