I'm trying to retrieve appointments whose "requiredattendees" contains on one of entities from account list. requiredattendees have a type of PartyList.
My query looks like:
var query = new QueryExpression("appointment")
{
ColumnSet = columnSet,
Criteria = new FilterExpression(LogicalOperator.Or)
};
And adding conditions :
GetAccounts()
.Select(a => new ConditionExpression("requiredattendees", ConditionOperator.Contains, a.Id))
.ForEach(c => query.Criteria.AddCondition(c));
a.Id is the account guid.
I'm getting following error:
Cannot add attribute requiredattendees of type partylist in a condition
System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=5.0.0.0, Culture=neutral]]
This code is for serviceappointment, but if i remember right, it's just the same for appointment. Hope this helps
QueryExpression qe = new QueryExpression
{
EntityName = "serviceappointment",
Criteria = new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression
{
AttributeName = "scheduledstart",
Operator = ConditionOperator.LessThan,
Values =
{
endTime
}
},
new ConditionExpression
{
AttributeName = "scheduledend",
Operator = ConditionOperator.GreaterThan,
Values =
{
startTime
}
}
}
},
LinkEntities =
{
new LinkEntity
{
LinkFromEntityName = "activitypointer",
LinkFromAttributeName = "activityid",
LinkToEntityName = "activityparty",
LinkToAttributeName = "activityid",
LinkCriteria = new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression
{
AttributeName = "partyid",
Operator = ConditionOperator.Equal,
Values =
{
someEntity.id
}
}
}
}
}
}
};
QueryExpression query = new QueryExpression(LetterEntityAttributeNames.EntityName)
{
ColumnSet = new ColumnSet(new string[]
{
LetterEntityAttributeNames.SubjectFieldName,
LetterEntityAttributeNames.RegardingObjectId,
LetterEntityAttributeNames.ToFieldName
}),
Criteria = new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression
{
AttributeName = LetterEntityAttributeNames.DirectChannelTypeFieldName,
Operator = ConditionOperator.Equal,
Values =
{
DirectChannelType
}
},
new ConditionExpression
{
AttributeName = LetterEntityAttributeNames.RegardingObjectId,
Operator = ConditionOperator.Equal,
Values =
{
RegardingId
}
}
}
},
LinkEntities =
{
new LinkEntity
{
LinkFromEntityName = ActivityPointerEntityAttributeNames.EntityName,
LinkFromAttributeName = ActivityPartyAttributeNames.ActivityId,
LinkToEntityName = ActivityPartyAttributeNames.EntityName,
LinkToAttributeName = CampaignActivityAttributeNames.Id,
LinkCriteria = new FilterExpression
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression
{
AttributeName = ActivityPointerAttributeNames.PartyIdField,
Operator = ConditionOperator.Equal,
Values =
{
ToEntityGuid
}
}
}
}
}
}
};
Related
I'm using the following code:
DynamoDBContextConfig config = new DynamoDBContextConfig()
{
ConsistentRead = false,
Conversion = DynamoDBEntryConversion.V2
};
using (DynamoDBContext context = new DynamoDBContext(config))
{
long unixTimestamp = (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
QTrackStatus qTrackStatus = new QTrackStatus()
{
Key = "m#m.com",
EventCode = "CC",
EventDateTime = "2019-09-09 14:00:30",
EventLocation = "BFS",
EventLastUpdate = unixTimestamp
};
DynamoDBOperationConfig dynamoDBOperationConfig = new DynamoDBOperationConfig()
{
QueryFilter = new List<ScanCondition>()
{
{ new ScanCondition("EventCode", ScanOperator.NotEqual, "CC") }
},
ConditionalOperator = ConditionalOperatorValues.And
};
await context.SaveAsync(qTrackStatus, dynamoDBOperationConfig);
}
What I'm trying to do is only save the record if the EventCode is not CC. Currently it's always saving. I could retrieve the record first, do a check and then call SaveAsync if required - however I'd like to do it all in the SaveAsync call. Is this possible?
Unless I've missed something, it doesn't look like this is possible with the higher level api. I ended up re-factoring to the following:
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
UpdateItemRequest updateItemRequest = new UpdateItemRequest()
{
TableName = "QTrackStatus",
ReturnValues = ReturnValue.ALL_NEW,
ConditionExpression = "EventCode <> :ec",
UpdateExpression = "SET EventCode = :ec, EventDateTime = :edt, EventLocation = :el, EventLastUpdate = :elu",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
{
{ ":ec", new AttributeValue("CC") },
{ ":edt", new AttributeValue("2019-09-09 14:00:30") },
{ ":el", new AttributeValue("BFS") },
{ ":elu", new AttributeValue() { N = ((long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds).ToString() } }
},
Key = new Dictionary<string, AttributeValue>()
{
{ "Key", new AttributeValue("m#m.com") }
}
};
try
{
UpdateItemResponse updateItemResponse = await client.UpdateItemAsync(updateItemRequest);
}
catch(ConditionalCheckFailedException e)
{
}
This allows me to achieve my goal.
I'm trying to make a query in order to retrieve all record containing one of the text in a string list.
QueryExpression query = new QueryExpression("account")
{
ColumnSet = new ColumnSet("primarycontactid", "new_text"),
NoLock = true,
Criteria =
{
Conditions =
{
new ConditionExpression()
{
AttributeName = "new_text",
Operator = ConditionOperator.In,
Values = { texts.ToArray() }
}
}
}
};
This code execute without issue, but don't return any record.
I also tried the following code, which resulted in the return of multiple record.
QueryExpression query = new QueryExpression("account")
{
ColumnSet = new ColumnSet("primarycontactid", "new_text"),
NoLock = true,
Criteria =
{
Conditions =
{
new ConditionExpression()
{
AttributeName = "new_text",
Operator = ConditionOperator.Equal,
Values = { texts.ToArray()[0] }
}
}
}
};
I also tried, without error, but with no return.
QueryExpression query = new QueryExpression("account")
{
ColumnSet = new ColumnSet("primarycontactid", "new_text"),
NoLock = true,
Criteria =
{
Conditions =
{
new ConditionExpression()
{
AttributeName = "new_text",
Operator = ConditionOperator.Equal,
Values = { texts.ToArray() }
}
}
}
};
How can I do in order to query with a list of values ?
The below syntax should work.
QueryExpression q = new QueryExpression("account");
q.Criteria.AddCondition("new_text", ConditionOperator.In, new object[] { "value1", "value2" });
Alternate version:
q.Criteria.AddCondition("new_text", ConditionOperator.In, "value1", "value2");
Read more
Here is one more approach.
Make your texts as list and then convert it to comma separated string and use this string in your condition
IList texts = new List{"1","2","testing"}; string joined = string.Join(",", texts);
Then you can use it as below
QueryExpression query = new QueryExpression("account") { ColumnSet = new ColumnSet("primarycontactid", "new_text"), NoLock = false, Criteria = { Conditions = { new ConditionExpression() { AttributeName = "new_text", Operator = ConditionOperator.In, Values = { joined } } } } };
Querying a table on Secondary Index, using a BeginsWith Operator does not always return the correct records. What could be the reason for that?
I have sample Code and tried it against a local DynamoDB table and against a table in AWS. The results are the same.
Defining the secondary index:
var gsiKey1Index = new GlobalSecondaryIndex
{
IndexName = "GSIKey1Index",
ProvisionedThroughput = new ProvisionedThroughput
{
ReadCapacityUnits = 1,
WriteCapacityUnits = 1
},
Projection = new Projection { ProjectionType = "ALL" }
};
var indexKey1Schema = new List<KeySchemaElement> {
{
new KeySchemaElement
{
AttributeName = "HashKey", KeyType = KeyType.HASH
}
}, //Partition key
{
new KeySchemaElement
{
AttributeName = "GSISortKey1", KeyType = KeyType.RANGE
}
} //Sort key
};
gsiKey1Index.KeySchema = indexKey1Schema;
Creating the table:
var request = new CreateTableRequest
{
TableName = "TestTable",
AttributeDefinitions = new List<AttributeDefinition>
{
new AttributeDefinition
{
AttributeName = "HashKey",
// "S" = string, "N" = number, and so on.
AttributeType = "S"
},
new AttributeDefinition
{
AttributeName = "SortKey",
AttributeType = "S"
},
new AttributeDefinition
{
AttributeName = "GSISortKey1",
// "S" = string, "N" = number, and so on.
AttributeType = "S"
},
},
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement
{
AttributeName = "HashKey",
// "HASH" = hash key, "RANGE" = range key.
KeyType = "HASH"
},
new KeySchemaElement
{
AttributeName = "SortKey",
KeyType = "RANGE"
},
},
GlobalSecondaryIndexes = { gsiKey1Index },
ProvisionedThroughput = new ProvisionedThroughput
{
ReadCapacityUnits = 10,
WriteCapacityUnits = 5
},
};
response2 = await _client.CreateTableAsync(request);
The Entity looks like this:
[DynamoDBTable("TestTable")]
public sealed class TestResult
{
[DynamoDBHashKey]
public string HashKey {get;set;}
public string SortKey {get;set;}
public string GSISortKey1 {get; set;}
}
The code to query looks like this:
public async Task<List<TestResult>> GetTestResultByDateTimeAsync(Guid hashid, Guid someId, string someName, DateTime timestamp)
{
var key2 = $"TR-{someId}-{someName}-{timestamp:yyyy-MM-ddTHH\\:mm\\:ss.fffZ}";
var key = $"TR-{someId}-{someName}-{timestamp:yyyy-MM-dd}";
//var filter = new QueryFilter();
//filter.AddCondition("HashKey", ScanOperator.Equal, hashid.ToString());
//filter.AddCondition("GSISortKey1", ScanOperator.BeginsWith, key);
//var queryConfig = new QueryOperationConfig
//{
// Filter = filter
//};
DynamoDBOperationConfig operationConfig = new DynamoDBOperationConfig()
{
OverrideTableName = "DEVTransponderTR",
IndexName = "GSIKey1Index",
QueryFilter = new List<ScanCondition>()
};
var sc = new ScanCondition("GSISortKey1", ScanOperator.BeginsWith, new[] { key });
operationConfig.QueryFilter.Add(sc);
var search = _context.QueryAsync<TestResult>(tenantid.ToString(), operationConfig);
var testresults = await search.GetRemainingAsync();
bool keywasok = true;
foreach (var testresult in testresults)
{
keywasok = testresult.GSISortKey1.StartsWith(key2) && keywasok;
}
if (keywasok) // this means I should find the same values if I use key2
{
DynamoDBOperationConfig operationConfig2 = new DynamoDBOperationConfig()
{
OverrideTableName = "TestTable",
IndexName = "GSIKey1Index",
QueryFilter = new List<ScanCondition>()
};
var sc2 = new ScanCondition("GSISortKey1", ScanOperator.BeginsWith, new[] { key2 });
operationConfig2.QueryFilter.Add(sc2);
var search2 = _context.QueryAsync<TestResult>(tenantid.ToString(), operationConfig);
var testresults2 = await search.GetRemainingAsync();
}
return testresults;
}
Then I add three instances to the table. importants is that all information is the same except the GSISortKey1 value. This is the GSISortKey1 value for the three items:
"TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-Open"
"TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-Send"
"TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-Test"
So in the example I first query on "BeginsWith" with a value of "TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02" (this is var key)
It returns all three items.
Then I check if the whole GSISortKey1 value of three returned items would also begin with the value "TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-", and that is true.
If that is true I just query again with a BeginsWith using the value "TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-"
It should return all three items. it returns 0 items.
I guess I am doing something wrong, some help appreciated.
I am trying to use AWS SDK for .NET Core.
Create a table to count views on videos.
Add a view count for a day.
Increment existing count for a day.
Query for video counts between two dates for a video.
.NET Core AWS SDK uses Async methods which are not documented in AWS. There is a feature request on their github page for this to happen.... but it is dated from last year. (https://github.com/aws/aws-sdk-net/issues/787)
CREATE THE TABLE
This works and creates a table on the AWS Console.
var ctRequest = new CreateTableRequest
{
AttributeDefinitions = new List<AttributeDefinition>()
{
new AttributeDefinition
{
AttributeName = "ViewUid",
AttributeType = ScalarAttributeType.S
},
new AttributeDefinition
{
AttributeName = "ViewDate",
AttributeType = ScalarAttributeType.S
}
},
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement
{
AttributeName = "ViewUid",
KeyType = KeyType.HASH //Partition key
},
new KeySchemaElement
{
AttributeName = "ViewDate",
KeyType = KeyType.RANGE
}
},
ProvisionedThroughput = new ProvisionedThroughput
{
ReadCapacityUnits = 5,
WriteCapacityUnits = 6
},
TableName = _settings.AWSDynamoDBViewCountTable
};
var response = _client.CreateTableAsync(ctRequest).Result;
UPDATE AND ITEM WITH AUTO-INCREMENT A FIELD
This, sadly, is where i hit issues. The old docs are found here under the Atomic Counter section. (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetItemCRUD.html)
Invalid ConditionExpression: Syntax error; token: \"SET\", near: \"SET
VC\"
var viewData = new Document();
viewData["ViewUid"] = videoUid; //Table entry UID
viewData["VideoId"] = videoId; // Video ID
viewData["ViewDate"] = date;
viewData["ViewCount"] = 0;
//Document result = await _viewCountTable.PutItemAsync(viewData);
Expression expr = new Expression();
expr.ExpressionStatement = "SET #VC = #VC + :val";
expr.ExpressionAttributeValues[":val"] = 1;
expr.ExpressionAttributeNames["#VC"] = "ViewCount";
var updateConfig = new UpdateItemOperationConfig() {
ConditionalExpression = expr,
ReturnValues = ReturnValues.UpdatedNewAttributes
};
var result = await _viewCountTable.UpdateItemAsync(viewData, updateConfig);
return result;
QUERY FOR DATE RANGE
Get one video's view count for a date range.
string queryTimeSpanStartString = dateFrom.ToString(AWSSDKUtils.ISO8601DateFormat);
string queryTimeSpanEndString = dateTo.ToString(AWSSDKUtils.ISO8601DateFormat);
var request = new QueryRequest
{
TableName = _settings.AWSDynamoDBViewCountTable,
KeyConditions = new Dictionary<string, Condition>()
{
{
"VideoId", new Condition()
{
ComparisonOperator = "EQ",
AttributeValueList = new List<AttributeValue>()
{
new AttributeValue { S = videoId }
}
}
},
{
"ViewDate",
new Condition
{
ComparisonOperator = "BETWEEN",
AttributeValueList = new List<AttributeValue>()
{
new AttributeValue { S = queryTimeSpanStartString },
new AttributeValue { S = queryTimeSpanEndString }
}
}
}
}
};
var response = await _client.QueryAsync(request);
Any help would be appreciated.
I was able to update the ViewCount with the following code:
string tableName = "videos";
var request = new UpdateItemRequest
{
Key = new Dictionary<string, AttributeValue>() { { "ViewUid", new AttributeValue { S = "replaceVideoIdhere" } } },
ExpressionAttributeNames = new Dictionary<string, string>()
{
{"#Q", "ViewCount"}
},
ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
{
{":incr", new AttributeValue {N = "1"}}
},
UpdateExpression = "SET #Q = #Q + :incr",
TableName = tableName
};
var response = await _dynamoDbClient.UpdateItemAsync(request);
I created a table called "videos" with a partition key named "ViewUid" as string. Let me know if this works for you.
I am trying to write the following a (pseudo)query in C# for CRM 4:
Status = active
AND
(
mail = somemail
OR
(
firstName like firstNameSearchTerm
AND
lastName like LastNameSearchTerm
)
)
The problem is, that middle names might be part of firstName or LastName. I am having a hard time putting this into ConditionExpressions / FilterExpressions.
#region mail conditions
// Create the ConditionExpression.
ConditionExpression mail1Condition = new ConditionExpression();
mail1Condition.AttributeName = "emailaddress1";
mail1Condition.Operator = ConditionOperator.Like;
mail1Condition.Values = new object[] { Registration.Email };
ConditionExpression mail2Condition = new ConditionExpression();
mail2Condition.AttributeName = "emailaddress2";
mail2Condition.Operator = ConditionOperator.Like;
mail2Condition.Values = new object[] { Registration.Email };
ConditionExpression mail3Condition = new ConditionExpression();
mail3Condition.AttributeName = "emailaddress3";
mail3Condition.Operator = ConditionOperator.Like;
mail3Condition.Values = new object[] { Registration.Email };
ConditionExpression statusCondition = new ConditionExpression();
statusCondition.AttributeName = "statuscode";
statusCondition.Operator = ConditionOperator.Equal;
statusCondition.Values = new object[] { "1" };
FilterExpression mailFilter = new FilterExpression();
mailFilter.FilterOperator = LogicalOperator.Or;
mailFilter.Conditions = new ConditionExpression[] { mail1Condition, mail2Condition, mail3Condition };
#endregion mail conditions
#region name conditions
/* FIRST NAME */
FilterExpression firstNameFilter = new FilterExpression();
firstNameFilter.FilterOperator = LogicalOperator.Or;
List<ConditionExpression> firstNameConditions = new List<ConditionExpression>();
var firstAndMiddleNames = Registration.FirstName.Trim().Split(' ');
firstAndMiddleNames = firstAndMiddleNames.Select(s => s.Replace(s, "%"+s+"%")).ToArray(); // Add wildcard search
foreach (var item in firstAndMiddleNames)
{
ConditionExpression firstNameCondition = new ConditionExpression();
firstNameCondition.AttributeName = "firstname";
firstNameCondition.Operator = ConditionOperator.Like;
firstNameCondition.Values = new object[] { item };
firstNameConditions.Add(firstNameCondition);
}
firstNameFilter.Conditions = firstNameConditions.ToArray();
/* LAST NAME */
FilterExpression lastNameFilter = new FilterExpression();
lastNameFilter.FilterOperator = LogicalOperator.Or;
List<ConditionExpression> lastNameConditions = new List<ConditionExpression>();
var lastAndMiddleNames = Registration.LastName.Trim().Split(' ');
lastAndMiddleNames = lastAndMiddleNames.Select(s => s.Replace(s, "%" + s + "%")).ToArray(); // Add wildcard search
foreach (var item in lastAndMiddleNames)
{
ConditionExpression lastNameCondition = new ConditionExpression();
lastNameCondition.AttributeName = "lastname";
lastNameCondition.Operator = ConditionOperator.Like;
lastNameCondition.Values = new object[] { item };
lastNameConditions.Add(lastNameCondition);
}
lastNameFilter.Conditions = firstNameConditions.ToArray();
#endregion name conditions
FilterExpression nameFilter = new FilterExpression();
nameFilter.FilterOperator = LogicalOperator.And;
nameFilter.Filters = new FilterExpression[] { firstNameFilter, lastNameFilter };
// Create the outer most filter to AND the state condition with the other filters
FilterExpression stateFilter = new FilterExpression();
stateFilter.FilterOperator = LogicalOperator.And;
stateFilter.Conditions = new ConditionExpression[] { statusCondition };
stateFilter.Filters = new FilterExpression[] { nameFilter };
query.EntityName = EntityName.contact.ToString();
query.Criteria = stateFilter;
query.ColumnSet = columns;
BusinessEntityCollection contacts = Service.RetrieveMultiple(query);
I
The query currently bypasses the mail filter for debugging purposes.
The result is that it finds all contacts matching the firstname or lastname (should be AND). Why???
There was a simple typo in the following line
lastNameFilter.Conditions = firstNameConditions.ToArray();
should be
lastNameFilter.Conditions = lastNameConditions.ToArray();