how can I access an attribute by name, rather than by integer? - c#

I must be missing something, but I can't seem to figure out how to get an Attribute by Name/String, only by an Integer, which is likely to change (the Attribute Name is not).
Could you explain how I get Attributes by name/string? The string "active" attempt produces this error:
Error 82 The best overloaded method match for 'System.Collections.Generic.List<Amazon.SimpleDB.Model.Attribute>.this[int]' has some invalid argumens
Thank you!
Hairgami
using (sdb = AWSClientFactory.CreateAmazonSimpleDBClient(accessKeyID, secretAccessKeyID))
{
String selectExpression = string.Format("select * from apps where appid = '{0}'", appID);
SelectRequest selectRequestAction = new SelectRequest().WithSelectExpression(selectExpression);
SelectResponse selectResponse = sdb.Select(selectRequestAction);
if (selectResponse.IsSetSelectResult())
{
SelectResult selectResult = selectResponse.SelectResult;
foreach (Item item in selectResult.Item)
{
//Works fine
Amazon.SimpleDB.Model.Attribute id = item.Attribute[1];
//How can I do this:
Amazon.SimpleDB.Model.Attribute id = item.Attribute["active"];
}
}
else
{
}
}

You're trying to access a System.Collections.Generic.List<T> like it's an associative array, which it's not. The Enumerable.FirstOrDefault method could be used to achieve something similar:
Amazon.SimpleDB.Model.Attribute id =
item.Attribute.FirstOrDefault(attr => attr.Name == "active");

Related

Dynamic linq filter children using pivot

I have business objects that look like the following:
class Project
{
public int ID
{
get;set;
}
public string ProjectName
{
get;set;
}
public IList<ProjectTag> ProjectTags
{
get;set;
}
}
class ProjectTag
{
public int ID
{
get;set;
}
public int ProjectID
{
get;set;
}
public string Name
{
get;set;
}
public string Value
{
get;set;
}
}
Example Data:
Project:
ID ProjectName
1 MyProject
ProjectTags:
ID ProjectID Name Value
1 1 Name 1 Value 1
2 1 Name 2 Value 2
3 1 Name 3 Value 3
Basically it's a way for our users to define their own columns on the Project. As a result, it's important to remember that I don't know the names of the ProjectTag entries at design time.
What I'm trying to accomplish is to give our users the ability to select projects based on search criteria using System.Linq.Dynamic. For instance, to select just the project in my example above, our users could enter this:
ProjectName == "MyProject"
The more complicated aspect is applying a filter to the ProjectTags. Our application currently allow users to do this in order to filter Projects by their ProjectTags:
ProjectTags.Any(Name == "Name 1" and Value == "Value 1")
That works, but starts to get a bit messy for end users to use. Ideally I'd like to write something that would let them do the following:
Name 1 == "Value 1"
Or if necessary (due to white space in the name), something like the following...
[Name 1] == "Value 1"
"Name 1" == "Value 1"
For lack of a better explanation, it seems like I want to do the equivalent of a SQL pivot on the ProjectTags, and then still be able to execute a where clause against that. I've looked at some of the questions on StackOverflow about pivots and dynamic pivoting, but I haven't found anything too useful.
I've also been thinking about looping through all the ProjectTag Names and building a dynamic query using a left join on each. I guess something like this:
select
Project.*,
Name1Table.Value [Name 1],
Name2Table.Value [Name 2],
Name3Table.Value [Name 3]
from
Project
left join ProjectTag Name1Table on Name = 'Name 1'
left join ProjectTag Name2Table on Name = 'Name 2'
left join ProjectTag Name3Table on Name = 'Name 3'
And then take that query and apply a where clause to it. But I'm not really sure how to do that in Linq as well as dealing with the white space in the name.
I also came across ExpandoObject. I thought possibly I could convert Project to an ExpandoObject. Then loop through all known ProjectTag names, adding each name to the ExpandoObject and, if that Project had a ProjectTag for that name, use that ProjectTag value as the value, else empty string. For example...
private static object Expand(
Project project,
List<string> projectTagNames)
{
var expando = new ExpandoObject();
var dictionary = (IDictionary<string, object>) expando;
foreach (var property in project.GetType()
.GetProperties())
{
dictionary.Add(property.Name, property.GetValue(project));
}
foreach (var tagName in projectTagNames)
{
var tagValue = project.ProjectTags.SingleOrDefault(p => p.Name.Equals(tagName));
dictionary.Add(tagName, tagValue?.Value ?? "");
}
return expando;
}
The exciting thing about this solution is I have an object that looks exactly like I think it should prior to filtering with a where clause. It even seems to accommodate spaces in the property name.
Then of course I found out that dynamic linq doesn't work nicely with ExpandoObject, and so it can't find the dynamic properties. I guess that's because it essentially has a type of Object which isn't going to define any of the dynamic properties. Maybe it's possible to generate a type at run time that matches? Even if that works, I don't think it can account for spaces in the Name.
Am I trying to accomplish too much with this functionality? Should I just tell the users to use syntax like ProjectTags.Any(Name == "Name1" and Value == "Value1")? Or is there some way to trick dynamic linq into understanding ExpandoObject? Seems like having a way to override the way dynamic linq resolves property names would be very handy.
How about using a translator to convert tag references?
I assume that tag names containing spaces will be surrounded by brackets ([]) and that Project field names are a known list.
public static class TagTranslator {
public static string Replace(this string s, Regex re, string news) => re.Replace(s, news);
public static string Surround(this string src, string beforeandafter) => $"{beforeandafter}{src}{beforeandafter}";
public static string SurroundIfMissing(this string src, string beforeandafter) => (src.StartsWith(beforeandafter) && src.EndsWith(beforeandafter)) ? src : src.Surround(beforeandafter);
public static string Translate(string q) {
var projectFields = new[] { "ID", "ProjectName", "ProjectTags" }.ToHashSet();
var opREStr = #"(?<op>==|!=|<>|<=|>=|<|>)";
var revOps = new[] {
new { Fwd = "==", Rev = "==" },
new { Fwd = "!=", Rev = "!=" },
new { Fwd = "<>", Rev = "<>" },
new { Fwd = "<=", Rev = ">=" },
new { Fwd = ">=", Rev = "<=" },
new { Fwd = "<", Rev = ">" },
new { Fwd = ">", Rev = "<" }
}.ToDictionary(p => p.Fwd, p => p.Rev);
var openRE = new Regex(#"^\[", RegexOptions.Compiled);
var closeRE = new Regex(#"\]$", RegexOptions.Compiled);
var termREStr = #"""[^""]+""|(?:\w|\.)+|\[[^]]+\]";
var term1REStr = $"(?<term1>{termREStr})";
var term2REStr = $"(?<term2>{termREStr})";
var wsREStr = #"\s?";
var exprRE = new Regex($"{term1REStr}{wsREStr}{opREStr}{wsREStr}{term2REStr}", RegexOptions.Compiled);
var tq = exprRE.Replace(q, m => {
var term1 = m.Groups["term1"].Captures[0].Value.Replace(openRE, "").Replace(closeRE, "");
var term1q = term1.SurroundIfMissing("\"");
var term2 = m.Groups["term2"].Captures[0].Value.Replace(openRE, "").Replace(closeRE, "");
var term2q = term2.SurroundIfMissing("\"");
var op = m.Groups["op"].Captures[0].Value;
if (!projectFields.Contains(term1) && !term1.StartsWith("\"")) { // term1 is Name, term2 is Value
return $"ProjectTags.Any(Name == {term1q} && Value {op} {term2})";
}
else if (!projectFields.Contains(term2) && !term2.StartsWith("\"")) { // term2 is Name, term1 is Value
return $"ProjectTags.Any(Name == {term2q} && Value {revOps[op]} {term1})";
}
else
return m.Value;
});
return tq;
}
}
Now you just translate your query:
var q = "ProjectName == \"Project1\" && [Name 1] == \"Value 1\" && [Name 3] == \"Value 3\"";
var tq = TagTranslator.Translate(q);

JObject Parse Data with a variable as the value

I am trying to decipher the correct syntax for using JObject Parse when I need to have one of the values set by a variable. This is for using Algolia to push a new object to my search index.
songIndexHelper.PartialUpdateObject(JObject.Parse(#"{""ApprovalFL"":"true",
""objectID"":"'+Accepted.Value+'"}"));
I receive Accepted.Value from my function argument. For example, Accepted.Value could equal something like 98. Also, true should be formatted as boolean instead of a string. The above is my attempt. How should I fix my syntax?
I'm following this documentation from Algolia: https://www.algolia.com/doc/api-reference/api-methods/partial-update-objects/
For more context, here is the above line in the function:
public ActionResult Index(int? Accepted, int? Denied)
{
var accountInfo = EntityDataAccess.GetAccountInfoByUserID(User.Identity.GetUserId());
if(accountInfo == null || accountInfo.AdminFL == false || accountInfo.LabelFL == true)
{
return RedirectToAction("Index", "Home");
}
else
{
if(Accepted != null)
{
EntityDataAccess.AcceptSong(Accepted.Value);
var songIndexHelper = HttpContext.Application.Get("SongIndexHelper") as IndexHelper<SongAlgoliaModel>;
songIndexHelper.PartialUpdateObject(JObject.Parse(#"{""ApprovalFL"":""true"",
""objectID"":""Accepted.Value""}"));
}
This should produce what you are looking for:
String json = "{\"ApprovalFL\":true,\"objectID\":" + Accepted.Value.ToString() + "}";
which is:
{"ApprovalFL":true,"objectID":98}
songIndexHelper.PartialUpdateObject(JObject.Parse(#"{""ApprovalFL"":""true"",
""objectID"":""Accepted.Value""}"));
should be:
songIndexHelper.PartialUpdateObject(JObject.Parse(#"{""ApprovalFL"":true,
""objectID"":" +Accepted.Value+ "}"));
The key is to use + to concatenate in the value of Accepted, and not wrap true in quotes.
Another approach I would suggest is not using strings at all. Consider an approach like:
var bob = new { ApprovalFL = true, objectID = Accepted.Value};
var obj = JObject.FromObject(bob);
songIndexHelper.PartialUpdateObject(obj);

Using Except keyword in c#

I am using the except keyword in c# for the first time and I have been struggling a lot with this. If possible could you please have a look into my function and let me know where I am wrong.
I need to return the string of arrays. indivEmails1 and indivEmails2 contains an array of email id's. I need to return an email id's which are not in indivEmails2 but not in indivEmails1. But it has to be string of array.
public string[] getNewCCEmailsIDs(WorkOrderModel model)
{
string[] emailids = null;
var result = _db.WorkOrders
.Where(w => w.idWorkOrder == model.idWorkOrder && w.idCompany == model.idCompany)
.Select(w => new {w.Status, w.ExternalEmails});
if (dbItem.Status == (int) WorkOrderStatus.Approved )
{
string NewCCEmail = "";
var comEmails1 = dbItem.ExternalEmails.Trim(';');
string[] indivEmails1 = comEmails1.Split(';');
string comEmails2 = model.ExternalEmails.Trim(';');
string[] indivEmails2 = comEmails2.Split(';');
IEnumerable<string> emailsToAdd = indivEmails2.Except(indivEmails1);
//NewCCEmail = emailsToAdd;
}
if (NewCCEmail != "") // when client delete an email id from CC and press save.
emailids = NewCCEmail.Split(';');
}
return emailids;
}
I am getting below error. I have looked eveywhere but no luck.
Error 54 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>' to 'string[]'. An explicit conversion exists (are you missing a cast?) C:\Users\Bakul\Documents\GitHub\Maxpanda\Maxpanda\Controllers\WorkOrderController.cs 930 25 Maxpanda
Any help will be very much appreciated.
Thanks.
Use ToList()
List<string> emailsToAdd = indivEmails2.Except(indivEmails1).ToList();
Thank you every one. Changed code to below and it worked.
string[] emailsToAdd = indivEmails2.Except(indivEmails1).ToArray();

'The given key was not present in the dictionary' - but the key exists

I am currently developing a MS Dynamics CRM 2013 - Plugin.
When I try to assign a string-value to a key of a field of an entity it gives me the 'keynotfound'-exception.
This leaves me clueless, because I can verify the key is existing. The key I give is also written correctly, and the data types are compatible, too.
Here's some extra info:
I tried resolving the issue with a server reboot. Nothing.
Remote Debugging is not an option.
I swapped "retrieved.EntityCollection.Entities[i][forField]" with retrieved.EntityCollection.Entities[i]["new_name"] and everything was working fine (kind of pointing out the obvious here, but "new_name" is not the key I try to access).
The execution stops # "if (retrieved.EntityCollection.Entities[i][forField].ToString() != "" && !overwriteExisting)"
Have you got an idea to help me out?
public void GenerateNumberForEntityCollection(string target)
{
try
{
// variables for number generation
bool overwriteExisting = (bool)preImageEntity["new_overwriteexisting"];
int suffixstart = (int)preImageEntity["new_suffixstart"];
string forField= preImageEntity["new_forfield"].ToString();
string prefix = preImageEntity["new_prefix"].ToString();
string postfix = preImageEntity["new_postfix"].ToString();
string separator = preImageEntity["new_separator"].ToString();
// Build query to get all the entries
RetrieveMultipleResponse retrieved;
int PageNumber = 1;
string PagingCookie = string.Empty;
int PageSize = 5000;
string[] Columns = { forField };
QueryExpression query = new QueryExpression()
{
EntityName = target,
ColumnSet = new ColumnSet(Columns),
PageInfo = new PagingInfo()
{
PageNumber = 1,
Count = PageSize
}
};
do
{
if (PageNumber != 1)
{
query.PageInfo.PageNumber = PageNumber;
query.PageInfo.PagingCookie = PagingCookie;
}
RetrieveMultipleRequest retrieve = new RetrieveMultipleRequest();
retrieve.Query = query;
retrieved = (RetrieveMultipleResponse)service.Execute(retrieve);
// Now that all entities are retrieved, iterate through them to gen. the numbers
int i = 0;
foreach (Entity entity in retrieved.EntityCollection.Entities)
{
if (retrieved.EntityCollection.Entities[i][forField].ToString() != "" && !overwriteExisting)
{
//continue;
}
else
{
retrieved.EntityCollection.Entities[i][forField] = prefix + separator + suffixstart.ToString() + separator + postfix;
}
suffixstart++;
service.Update(retrieved.EntityCollection.Entities[i]);
i++;
}
if (retrieved.EntityCollection.MoreRecords)
{
PageNumber++;
PagingCookie = retrieved.EntityCollection.PagingCookie;
}
} while (retrieved.EntityCollection.MoreRecords);
}
catch (Exception e)
{
tracing.Trace("GenerateNumberForEntityCollection: Failed: {0}", e.ToString());
}
}
How did you verify that the key exists?
If the data in a field is null, the Entity instance will not contain that key, even if you specify it in the query's ColumnSet.
This will return you a boolean, indicating if the key exists in the Entity. You can do this control before attempting to read the attribute.
var attributeExists = retrieved.EntityCollection.Entities[i].Contains(forField)
The control below you've done will result in the exception you're getting if the field is null. Just make sure that the attribute exists before.
retrieved.EntityCollection.Entities[i][forField].ToString() != ""
Additionally, you'll get a null reference exception if no records were returned from the query. Make you do a null check on retrieved.EntityCollection.Entities.
When you are querying data in Dynamics CRM it is important to know that record fields having null values in the database are not included in the Attributes collection of the Entity instances being returned.
Getting a value from an Entity's Attribute with this construct:
var value = retrieved.EntityCollection.Entities[i][forField].ToString();
succeeds when attribute forField already has a value in the database, but fails when its current value is null.
Therefore the preferred method to get the attribute values from an entity is GetAttributeValue<T>, like this:
var value = retrieved.EntityCollection.Entities[i].getAttributeValue<string>(forField);
This method returns the value when the attribute exists in the attribute collection, otherwise it returns null.
If any of the fields among
(new_forfield,new_prefix,new_postfix,new_separator) has null value,
that column does not present in the retrieved object and you are trying to get the value of null column preImageEntity["new_forfield"] which will throw keynotfound'-exception ,
so change the code
string forField= preImageEntity["new_forfield"].ToString();
string prefix = preImageEntity["new_prefix"].ToString();
string postfix = preImageEntity["new_postfix"].ToString();
string separator = preImageEntity["new_separator"].ToString();
to
string forField = preImageEntity.Attributes.Contains("new_forfield")? preImageEntity["new_forfield"].ToString():"";
string prefix = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_prefix"].ToString() : "";
string postfix = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_postfix"].ToString() : "";
string separator = preImageEntity.Attributes.Contains("new_forfield") ? preImageEntity["new_separator"].ToString() : "";
this will check for field, if it exists than will parse the value to
string else will assign empty string.

The input string was not in the correct format

i'm getting an error in this piece of code with asp.net mvc 4 "input string was not in a correct format" i know why i get this error because im making a search filter by Marca (Brand, im making it in spanish), the dropdownlist where the brands are in a table are in string value, but the row in the Items Table where they are related is an int value. The search results http post tries to do it with string values and i get the error, if i type manually in the url the int id of the brand i want to search the query passes. Here is an example of my code and sorry for my bad english.
public ActionResult Index(string marcas, string search_query)
{
var MarcaLst = new List<string>();
var MarcaQry = from d in db.Marcas // table Brand
orderby d.Marca1 // string row of the table Brand
select d.Marca1;
MarcaLst.AddRange(MarcaQry.Distinct());
ViewBag.marcas = new SelectList(MarcaLst);
var marca = from m in db.Marcas
select m;
if (!String.IsNullOrEmpty(search_query))
{
descripcion = descripcion.Where(s => s.Descripcion.ToUpper().Contains(search_query.ToUpper()));
}
if (string.IsNullOrEmpty(marcas))
return View(descripcion.ToList());
else
{
int marcasint = Convert.ToInt32(marcas); // I get the error here from a work around to make the page load
return View(descripcion.Where(x => x.MarcaID == marcasint)); //MarcaID is the int value of the Items table for the Brand
}
}
url/articulos?search_query=a&marcas=BSN //Error
url/articulos?search_query=a&marcas=1 //Pass
You are trying to convert string to integer.So the string must be in the right format.For example, You cannot convert "abc1" to integer. You can use Int32.TryParse(stringVal) to check for possiblity of type conversion and convert. The above method returns boolean.
Don't just throw in a string to Convert and assume it's a valid integer if it's not null or empty. Use TryParse instead:
int marcasint;
bool success = Int32.TryParse(marcas, out marcasint);
if (success){
return View(descripcion.Where(x => x.MarcaID == marcasint));
} else {
return View(descripcion.ToList());
}
try the Int32.TryParse method to try to convert the string to a integer. All major number formats have the TryParse methods:
Documentation:
http://msdn.microsoft.com/en-us/library/f02979c7.aspx
Try using TryParse method
int marcasint;
if(Int32.TryParse(marcas, out marcasint))
{
return View(descripcion.Where(x => x.MarcaID == marcasint));
}
else
{
//change eles part as required.
return View(descripcion.Where(x => x.MarcaID == -1));
}
After reading your comments, I think you don't need to filter records by MarcaID but it's name. So try this and replace BrandName with correct field name.
return View(descripcion.Where(x => x.BrandName == marcas));

Categories