Creating Sort and Partition Keys on DynamoDb - c#

Getting this error when creating a table:
"One or more parameter values were invalid:
Number of attributes in KeySchema does not
exactly match number of attributes defined in AttributeDefinitions"
I followed the example here
I have my keyed attributes in both sections. The only thing I am wondering about is that my keyed attribute types are strings, not numbers. I was not able to find an answer one way or the other on that one.
My implementation
private static void CreateTableMember()
{
string tableName = "Member";
var response = client.CreateTable(new CreateTableRequest
{
TableName = tableName,
AttributeDefinitions = new List<AttributeDefinition>()
{
new AttributeDefinition
{
AttributeName = "MasterCustomerId",
AttributeType = "S"
},
new AttributeDefinition
{
AttributeName = "LastName",
AttributeType = "S"
},
new AttributeDefinition
{
AttributeName = "DistrictId",
AttributeType = "S"
},
new AttributeDefinition
{
AttributeName = "EmailAddress",
AttributeType = "S"
},
new AttributeDefinition
{
AttributeName = "FirstName",
AttributeType = "S"
}
},
KeySchema = new List<KeySchemaElement>()
{
new KeySchemaElement
{
AttributeName = "MasterCustomerId",
KeyType = "HASH" // Partition Key
},
new KeySchemaElement
{
AttributeName = "LastName",
KeyType = "RANGE" //Sort key
}
},
ProvisionedThroughput = new ProvisionedThroughput
{
ReadCapacityUnits = 10,
WriteCapacityUnits = 5
}
});
WaitTillTableCreated(client, tableName, response);
}

You do not need to specify non-key attributes when creating a DynamoDB table. DynamoDB does not have a fixed schema. Instead, each data item may have a different number of attributes (aside from the mandatory key attributes).
Removing the non-keyed attributes fixed the issue

Related

How can I use begins_with method on sort key using c# in DynamoDB

If I was to use the high level model, I might try something like this:
public async void GetBooksData()
{
GetItemRequest request = new GetItemRequest
{
TableName = "Customer",
Key = new Dictionary<string, AttributeValue>
{
{"UserName", new AttributeValue{S="a"} },
{"BookNum", new AttributeValue { S = starts_with(queryTerm)} }
}
};
try
{
var response = await client.GetItemAsync(request);
if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
{
if (response.Item.Count > 0)
{
foreach (var item in response.Item)
{
MessageBox.Show("Value : \n" + item.Value.S);
}
}
}
}
catch (InternalServerErrorException iee)
{
MessageBox.Show(iee);
}
}
I need to use the method 'begins_with' for getting 2 items what UserName is 'a' and the BookNum are book_1 and book_2. This is possible in the high level interface in Java. As an example as to what can be done on the range key in Java:
public List<Comment> allForItemWithMinRating(String itemId, int minRating) {
Comment comment = new Comment();
comment.setItemId(itemId);
Condition condition = new Condition()
.withComparisonOperator(ComparisonOperator.GE)
.withAttributeValueList(
new AttributeValue()
.withN(Integer.toString(minRating)));
DynamoDBQueryExpression<Comment> queryExpression
= new DynamoDBQueryExpression<Comment>()
.withHashKeyValues(comment)
.withRangeKeyCondition(
"rating",
condition
)
.withScanIndexForward(false);
return mapper.query(Comment.class, queryExpression);
}
In the low level interface for C# you can achieve this as so:
var requestDynamodb = new QueryRequest
{
TableName = "GroupEdEntries",
KeyConditionExpression = "partition_key = :s_Id and begins_with(sort_key, :sort)",
ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
{":s_Id", new AttributeValue { S = my_id }},
{":sort", new AttributeValue { S = sort_key_starts_with }}
},
ConsistentRead = true
};
var results = await client.QueryAsync(requestDynamodb);
where the keys are called partition_key and sort_key. However, this returns the results as attribute values, which then need to be converted into POCOs one property at a time. It requires using reflection and is made more complicated using converters. It seems strange that this fundamental functionality (as well as other functionality) isn't supported in the C# SDK.
I ended up using reflection to create the tables based on the attributes, when this is also supported by default in Java. Am I missing a high level API for C#?
It's a bit of a different syntax and I can't find it documented anywhere (other than in code comments), but this works for me:
string partition_key = "123";
string sort_key_starts_with = "#type"
List<object> queryVal = new List<object>();
queryVal.Add(sort_key_starts_with);
var myQuery = context.QueryAsync<GroupEdEntry>(partition_key, QueryOperator.BeginsWith, queryVal);
var queryResult = await myQuery.GetRemainingAsync();

pass to the SSRS report multiple integer values

I try to pass to a SSRS report, from the C# code multiple arrays of integer
var rsExec = new ReportExecutionServiceSoapClient(binding, new EndpointAddress(config.ReportExecutionUrl));
ParameterValue[] reportParam = new ParameterValue[] {
new ParameterValue { Name = "pCityId", Value = cityId.ToString() },
new ParameterValue { Name = "pDepartmentIds", Value = string.Join(",", departmentIds) },
new ParameterValue { Name = "pBuildingIds", Value = string.Join(",", buidingIds) }
};
await rsExec.SetExecutionParametersAsync(null, null, reportParam, "en-us");
as the Value type of ParameterValue is "string", it seems I have no choice but passing a CSV as parameter to the report.
Then, in the report I can use data type as integer, and say that I am passing "multiple values", but how to do it from the C# code?
PS. Related to that question
To send parameters where the Allow multiple values option is selected, you need to send a new ParameterValue object for each value that is going to be consumed by the report, all with the same Name.
In the case described above, you need to send a ParameterValue for each value in the departmentIds collection, all with the same parameter name ("pDepartmentIds").
So, if there was 3 department IDs to send, the reportParam array should contain 3 ParameterValue objects, all with the name "pDepartmentIds", one for each department ID.
ParameterValue[] reportParam = new ParameterValue[] {
new ParameterValue { Name = "pCityId", Value = cityId.ToString() },
new ParameterValue { Name = "pDepartmentIds", Value = "1" },
new ParameterValue { Name = "pDepartmentIds", Value = "2" },
new ParameterValue { Name = "pDepartmentIds", Value = "3" },
...
};
Do something similar for buildingIds.

How to choose certain values from ICollection to IDictionary, using LINQ

I have IDictionary<int,bool?> where int - id, bool? - state (true,false,null)
So i need to filter ICollection of objects, where i should compare internal id with id of my IDictionary and if IDs are the same and the state is true - i should select this element (using LINQ)
I tried: incomeCollection.Values.Select(x=>x.InternalId.Equals(dataFromDictionary.Keys.Any)).Select(h=> new Item){Item = h.Name}
but it does not works. I need to check all collection and select elements, which satisfy the condition above using LINQ. How can i do this?
The dictionary has a handy TryGetValue method allowing to look up an entry quickly.
class Income
{
public int InternalId { get; set; }
public string Name { get; set; }
}
var dictionary = new Dictionary<int,bool?>
{
{1, false},
{2, true},
{3, null},
};
var incomeCollection = new List<Income>
{
new Income { InternalId = 1, Name = "A" },
new Income { InternalId = 2, Name = "B" },
new Income { InternalId = 3, Name = "C" },
new Income { InternalId = 4, Name = "D" },
};
var result = incomeCollection.Where(x =>
dictionary.TryGetValue(x.InternalId, out var status) && status == true)
.Select(h=> new {Item = h.Name});
This is better than your first approach using dataFromDictionary.Keys.Any which does not take advantage of the Dictionary feature of quick lookup.
You can use Any()
var result = list.Where(x=>dictionary.Keys.Any(c=>c.Equals(x.Id)) && x.State.HasValue && x.State==true).Select(x=>x);
You can also use Join.
var result = list.Join(dictionary,
l=>l.Id,
d=>d.Key,(l,d)=>l)
.Where(x=>x.State.HasValue && x.State==true).Select(x=>x);
For example,
var dictionary = new Dictionary<int,bool?>
{
[1] = true,
[3] = true,
[35] = false
};
var list = new List<Person>
{
new Person{Name="Jia", Id=1,State=false},
new Person{Name="Aami", Id=3,State=true},
new Person{Name="Anu", Id=35,State=null},
};
Output
Aami 3 True
ToDictionary method can be used as shown in the below example.
In order to select only few values from ICollection you can use where clause.
List<Package> packages =
new List<Package>
{ new Package { Company = "Coho Vineyard", Weight = 25.2, TrackingNumber = 89453312L },
new Package { Company = "Lucerne Publishing", Weight = 18.7, TrackingNumber = 89112755L },
new Package { Company = "Wingtip Toys", Weight = 6.0, TrackingNumber = 299456122L },
new Package { Company = "Adventure Works", Weight = 33.8, TrackingNumber = 4665518773L } };
// Create a Dictionary of Package objects,
// using TrackingNumber as the key.
Dictionary<long, Package> dictionary =
packages.ToDictionary(p => p.TrackingNumber);
foreach (KeyValuePair<long, Package> kvp in dictionary)
{
Console.WriteLine(
"Key {0}: {1}, {2} pounds",
kvp.Key,
kvp.Value.Company,
kvp.Value.Weight);
}

how to Add nested object models to the list?

I have some object models like this :
var x= new XModel()
{
end_date = "2017-12-15",
page = 1,
start_date = "2014-12-01",
group_by = new List<string> { "numbers" },
filter = new Filter() { numbers= new List<int> {1620} ,names= null, deleted= null, added = null }
};
or this one :
var y= new YModel
{
Title = "test title",
GenderType = Gender.Men,
Oss = "ALL",
Devices = new List<string> { "11", "12" },
Categories = new List<string> { "11", "12" },
}
i want to add these models to the list, the problem is , i tried to wrote a generic method to add all object models like above to the list.
My current method is :
internal static List<UrlParameter> GetParams<TModel>(this TModel entity)
{
var parameters = new List<UrlParameter>();
foreach (var propertyInfo in entity.GetType().GetProperties())
{
var propVal = propertyInfo.GetValue(entity, null);
if (propVal == null)
{
parameters.Add(new UrlParameter(propertyInfo.Name, ""));
continue;
}
if (propertyInfo.PropertyType.IsGenericType)
{
if (propVal.GetType().IsPrimitiveType())
{
parameters.Add(new UrlParameter(propertyInfo.Name, propVal));
}
else
{
var arr = propVal as IEnumerable;
if (arr.HasArrayContainPrimitiveType())
parameters.Add(new UrlParameter(propertyInfo.Name, $"[{ToJsonArray(arr)}]"));
else
parameters.AddRange(from object obj in arr
select GetParams(obj)
into subparams
select new UrlParameter(propertyInfo.Name, subparams));
}
}
else
{
if (propVal.GetType().IsPrimitiveType())
parameters.Add(new UrlParameter(propertyInfo.Name, propVal));
else
{
var subparams = GetParams(propVal);
parameters.Add(new UrlParameter(propertyInfo.Name, subparams));
}
}
}
return parameters;
}
it works fine for most of my models, but the x where contains filter makes me a problem, the numbers value saved like this filter=numbers%3d%255b1620%255d%2c%2c%2c%2c%2c%2c%2c , and the rest of the fields disappeare.
i want to add numbers, names, deleted and added as key, value parameter nested in filter, can you please help me to fixed this?
I solved my problem by using MultipartFormDataContent class.
it converts all the nested model as they are.

Create a SuiteTalk transaction search that gets all sales order with a certain status

In NetSuite SuiteTalk (Web Services), I am trying to create a search that will find all sales orders that have the status "Pending Approval". I think I have everything structured correctly and I think the problem is the status is not actually called "Pending Approval, but something else. I have tried other variants like "_pendingApproval", but my search never returns any results. If I comment out the status part, the search works correctly and returns every sales order for this particular customer.
Any thoughts on what the problem is?
C#
TransactionSearchBasic tsb = new TransactionSearchBasic() {
mainLine = new SearchBooleanField() {
searchValue = true,
searchValueSpecified = true,
},
type = new SearchEnumMultiSelectField() {
#operator = SearchEnumMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new string[] { "_salesOrder" },
},
entity = new SearchMultiSelectField() {
#operator = SearchMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new RecordRef[] {
new RecordRef() {
type = RecordType.customer,
internalId = "231"
}
}
},
status = new SearchEnumMultiSelectField() {
#operator = SearchEnumMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new string[] {
"Pending Approval",
"_pendingApproval",
"pendingApproval",
"pendingapproval",
"pending approval",
"0"
}
}
};
SearchResult results = _nss.search(tsb);
It looks like the type of transaction needs to be prefixed to the status. For example:
status = new SearchEnumMultiSelectField() {
#operator = SearchEnumMultiSelectFieldOperator.anyOf,
operatorSpecified = true,
searchValue = new string[] {
"_salesOrderPendingApproval"
}
}
Try using :
"pendingApproval"
instead of
"_pendingApproval" & "Pending Approval"

Categories

Resources