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

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

Related

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>.

dynamodb scan: filter all records where attribute does not exist

I can't seem to get this right.
I want to do a scan of a table and only return records where a particular field does not exist.
I've tried the following two things:
HashMap<String, Condition> scanFilter = new HashMap();
Condition scanFilterCondition = new Condition().withComparisonOperator(ComparisonOperator.NULL.toString());
scanFilter.put("field", scanFilterCondition);
ScanRequest scan = new ScanRequest()
.withTableName("table name")
.withScanFilter(scanFilter)
etc
and
ScanRequest scan = new ScanRequest()
.withTableName("table")
.withFilterExpression("attribute_not_exists(attributeName)")
.withLimit(100)
etc
However they return no records (and most records are missing this field). Note, that if I remove the filter the scan does return and process all records as expected so the basic query is correct.
How do I do this?
EDIT added full method in case it helps
// Get information on the table so that we can set the read capacity for the operation.
List<String> tables = client.listTables().getTableNames();
String tableName = tables.stream().filter(table -> table.equals(configuration.getTableName())).findFirst().get();
if(Strings.isNullOrEmpty(tableName))
return 0;
TableDescription table = client.describeTable(tableName).getTable();
//Set the rate limit to a third of the provisioned read capacity.
int rateLimit = (int) (table.getProvisionedThroughput().getReadCapacityUnits() / 3);
RateLimiter rateLimiter = RateLimiter.create(rateLimit);
// Track how much throughput we consume on each page
int permitsToConsume = 1;
// Initialize the pagination token
Map<String, AttributeValue> exclusiveStartKey = null;
int count = 1;
int writtenCount = 0;
do {
// Let the rate limiter wait until our desired throughput "recharges"
rateLimiter.acquire(permitsToConsume);
//We only want to process records that don't have the field key set.
HashMap<String, Condition> scanFilter = new HashMap<>();
Condition scanFilterCondition = new Condition().withComparisonOperator(ComparisonOperator.NULL.toString());
scanFilter.put("field", scanFilterCondition);
ScanRequest scan = new ScanRequest()
.withTableName(configuration.getNotificationsTableName())
.withScanFilter(scanFilter)
.withLimit(100)
.withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
.withExclusiveStartKey(exclusiveStartKey);
ScanResult result = client.scan(scan);
exclusiveStartKey = result.getLastEvaluatedKey();
// Account for the rest of the throughput we consumed,
// now that we know how much that scan request cost
double consumedCapacity = result.getConsumedCapacity().getCapacityUnits();
permitsToConsume = (int)(consumedCapacity - 1.0);
if(permitsToConsume <= 0) {
permitsToConsume = 1;
}
// Process results here
} while (exclusiveStartKey != null);
The NULL condition seems to be fine. You need to do recursive search using Scan. The Dynamodb scan doesn't scan the whole database in one go. It scans the data based on the amount of consumed provisioned throughput.
Sample code to perform scan in loop based on LastEvaluatedKey:-
ScanResult result = null;
do {
HashMap<String, Condition> scanFilter = new HashMap<>();
Condition scanFilterCondition = new Condition().withComparisonOperator(ComparisonOperator.NULL);
scanFilter.put("title", scanFilterCondition);
ScanRequest scanRequest = new ScanRequest().withTableName(tableName).withScanFilter(scanFilter);
if (result != null) {
scanRequest.setExclusiveStartKey(result.getLastEvaluatedKey());
}
result = dynamoDBClient.scan(scanRequest);
LOGGER.info("Number of records ==============>" + result.getItems().size());
for (Map<String, AttributeValue> item : result.getItems()) {
LOGGER.info("Movies ==================>" + item.get("title"));
}
} while (result.getLastEvaluatedKey() != null);
NULL : The attribute does not exist. NULL is supported for all data
types, including lists and maps. Note This operator tests for the
nonexistence of an attribute, not its data type. If the data type of
attribute "a" is null, and you evaluate it using NULL, the result is a
Boolean false. This is because the attribute "a" exists; its data type
is not relevant to the NULL comparison operator.
LastEvaluatedKey The primary key of the item where the operation
stopped, inclusive of the previous result set. Use this value to start
a new operation, excluding this value in the new request.
If LastEvaluatedKey is empty, then the "last page" of results has been
processed and there is no more data to be retrieved.
If LastEvaluatedKey is not empty, it does not necessarily mean that
there is more data in the result set. The only way to know when you
have reached the end of the result set is when LastEvaluatedKey is
empty.
var expr = new Expression();
expr.ExpressionStatement = "contains(#Name, :Name) and attribute_not_exists(#FullName) or #FullName = :FullName";
expr.ExpressionAttributeNames["#FullName"] = "FullName";
expr.ExpressionAttributeValues[":FullName"] = "sumit singh";
expr.ExpressionAttributeNames["#Name"] = "Name";
expr.ExpressionAttributeValues[":Name"] = "sumit singh";
ScanOperationConfig config = new ScanOperationConfig()
{
Limit = 2,
PaginationToken = "{}",
//Filter = filter,
FilterExpression = expr,
//AttributesToGet = attributesToGet,
//Select = SelectValues.SpecificAttributes,
TotalSegments = 1
};
var item = _tableContext.FromScanTableAsync(config);
do
{
documentList.AddRange(await item.GetNextSetAsync());
} while (!item.IsDone);

push data from web form into CRM 2015 with duplicate detection before creating new records inside CRM

Guys.
I have a web form to push metadata into CRM 2015 online by creating new records. But before creating new records in CRM, I would like to check if this records(First Name, Last Name, DOB) duplicate or not. If duplicates, updates the existing record, If not, create a new record.
My current idea is, that on the web form(ASP.NET APP) retrieve all records(Names, DOB) and compare with input metadata, if match, updates or creates new record. But I am not sure if there is simple way to do this.
Do you have any suggestion?
Appreciate it.
I think I just got it.
bool hasDulicate = false;
//duplicate detection
FilterExpression codeFilter = new FilterExpression(LogicalOperator.And);
codeFilter.AddCondition("firstname", ConditionOperator.Equal, firstname.Text);
codeFilter.AddCondition("lastname", ConditionOperator.Equal, lastname.Text);
QueryExpression query = new QueryExpression
{
EntityName = "contact",
ColumnSet = new ColumnSet(true), // we assume you want to retrieve all the fields
Criteria = codeFilter
};
EntityCollection records = service.RetrieveMultiple(query);
int totalrecords = records.Entities.Count;
foreach (Entity record in records.Entities)
{
if (record["emailaddress1"] != null)
{
record["emailaddress1"] = email.Text;
record["mobilephone"] = phone.Text;
proxy.Update(record);
hasDulicate = true;
}
}
if (hasDulicate == false)
{
Entity contact = new Entity("contact");
contact["firstname"] = Convert.ToString(firstname.Text);
contact["lastname"] = Convert.ToString(lastname.Text);
contact["emailaddress1"] = Convert.ToString(email.Text);
contact["mobilephone"] = Convert.ToString(phone.Text);
Guid conid = proxy.Create(contact);
}

ASIN List on Products API?

Morning,
I am trying to pass a list of Amazon ASIN's so i can process them using the MWS API.
List<string> prodASINs = dc.aboProducts.Select(a => a.asin).ToList();
var count = prodASINs.Count();
//Loop through passing 10 at a time to AWS
for (var i = 0; i < count; i++)
{
var prodASINToSend = prodASINs.Skip(i * 10).Take(10).ToList();
//Send to AWS
MarketplaceWebServiceProductsConfig config = new MarketplaceWebServiceProductsConfig();
config.ServiceURL = productsURL;
MarketplaceWebServiceProducts.MarketplaceWebServiceProductsClient service = new MarketplaceWebServiceProductsClient(appname, version, accesskeyID, secretkey, config);
GetLowestOfferListingsForASINRequest request = new GetLowestOfferListingsForASINRequest();
request.SellerId = merchantID;
request.MarketplaceId = marketids[0];
request.ItemCondition = condition;
request.ASINList.ASIN = prodASINToSend;
However the request.ASINList.ASIN = prodASINToSend; is saying "Object reference not set to an instance of an object." However it is passing over the required List<string> prodASINToSend
Could anyone shed some light on this for em please?
The error means you forgot to declare a new instance of a class before trying to use the class object.
In your case the ASINList will need to be declared as a new instance of the ASINList class.

EF 4.1 Code First adding to a foreign key collection

If I have an entity with a collection property for another entity. What is the best way to add a new entity and it's related entities? The problem I have is that the collection is initially null.
var form = new Form()
{
Name = "TestForm"
};
ctx.Forms.Add(form);
var formField = new FormField()
{
Name = "TestField"
};
form.FormFields.Add(formField);
ctx.SaveChanges();
The form.FormFields property above is null so I get an exception. I know I could set the relationship in the other direction but I haven't defined a Form property on FormFields (and I don't really want to).
So what is the cleanest solution to for this?
The simplest solution is to initialize the collection like this:
var form = new Form() {
Name = "TestForm"
};
ctx.Forms.Add(form);
var formField = new FormField() {
Name = "TestField"
};
if(form.FormFields == null)
form.FormFields = new List<FormField>();
form.FormFields.Add(formField);
ctx.SaveChanges();

Resources