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 complete method should be generic like
public string strGetMaxValue(string strDBName, string strCollectionName, string strKey)
{
// in this method if pass some prms it should give max value
}
The one i tried is
string strMaxValue = "";
MongoServer objServer = this.ConnectToServer();
if ((strDBName != null || strDBName != "") && (strCollectionName != null || strCollectionName != ""))
{
string[] strArrays = new string[1];
strArrays[0] = strKey;
//MongoCursor<BsonDocument> objCursor = objServer.GetDatabase(strDBName).GetCollection(strCollectionName).Find(query).SetSortOrder(SortBy.Descending(strArrays)).SetLimit(1);
var objCursor = objServer.GetDatabase(strDBName).GetCollection(strCollectionName).FindAll().SetSortOrder(SortBy.Descending(strArrays)).SetLimit(1).ToArray();
}
In that objCursor i m getting that document which i need.
i want to extract that field value and needs to send it as return parameter.
The method should be generic as such the key value may a field in nested document also.
how to achieve this.?
The method you are looking for is SetFields(params string[] fields) - it can be called on a cursor. It will limit your result set to just the fields you pass in (array) as well as the id. You can then index the field using the []
var result = server
.GetDatabase(strDBName)
.GetCollection(strCollectionName)
.FindAll()
.SetSortOrder(SortBy.Descending(new [] {strKey}))
.SetFields(new [] {strKey}) // The way to wrap something in an array for reference
.SetLimit(1)
.FirstOrDefault(); // Will return null if there are no rows
// There is a chance that we have no results
if (result != null)
// You might want to make sure this is a string / add the datatype
// as a Generic T to your function
return result[strKey].AsString;
else
return null;
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));
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");
I have the following code:
string Keys = string.Join(",",FormValues.AllKeys);
I was trying to play around with the get:
string Values = string.Join(",", FormValues.AllKeys.GetValue());
But of course that doesn't work.
I need something similar to get all the values, but I don't seem to find the appropriate code to do the same.
P.S: I do not want to use a foreach loop since that beats the purpose of the first line of code.
var col = new NameValueCollection() { { "a", "b" }, { "1", "2" } }; // collection initializer
var values = col.Cast<string>().Select(e => col[e]); // b, 2
var str = String.Join(",", values ); // "b,2"
Also you can create an extension method:
public static string Join(this NameValueCollection collection, Func<string,string> selector, string separator)
{
return String.Join(separator, collection.Cast<string>().Select(e => selector(e)));
}
Usage:
var s = c.Join(e => String.Format("\"{0}\"", c[e]), ",");
Also you can easily convert NameValueCollection to more handy Dictionary<string,string> so:
public static IDictionary<string,string> ToDictionary(this NameValueCollection col)
{
return col.AllKeys.ToDictionary(x => x, x => col[x]);
}
Gives:
var d = c.ToDictionary();
As I found using Reflector, NameValueCollection.AllKeys internally performs a loop to gather all te keys, so it seems that c.Cast<string>() is more preferable.
string values = string.Join(",", collection.AllKeys.Select(key => collection[key]));
Following creates a string from URL parameter list.
string.Join(", ",
Request.QueryString
.AllKeys
.Select(key => key + ": " + Request.QueryString[key])
.ToArray())
i.e
page.aspx?id=75&page=3&size=7&user=mamaci
would be
id: 75, page: 3, size: 7, user: mamaci
string values =
string.Join(",", FormValues.AllKeys.SelectMany(key => FormValues.GetValues(key)));
Edit: The other answers may or may not be what you want. They appear simpler, but the results might not be what you are looking for in all circumstances, but then again, they might be (your mileage may vary).
Note that a NameValueCollection is not a 1:1 mapping like a dictionary. You can add multiple values for the same key, which is why a function like .GetValues(key) returns an array, not a single string.
If you have a collection where you have added
collection.Add("Alpha", "1");
collection.Add("Alpha", "2");
collection.Add("Beta", "3");
Retrieving collection["Alpha"] yields "1,2". Retrieving collection.GetValues("Alpha") yields { "1", "2" }. Now, it just so happens that you are using a comma to join your values together into a single string, so this disparity is hidden. However, if you were joining on another value, such as an exclamation point, the results of the other answers would be
"1,2!3"
And the code here would be
"1!2!3"
Use the snippet that demonstrates the behavior you prefer.
In cases where you have parsed the query string with System.Web.HttpUtility.ParseQueryString(...) you can just use ToString() and you don't have to re-invent the wheel.
Even though result is NameValueCollection, the underlying type is HttpValueCollection which has the necessary ToString() override to build back a query string.
I'm using Azure DocumentDB as my logging mechanism, hence writing a dynamic object, but you get the gist...
public class LogErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
int responseCode = new int();
// Has the exception been handled. Also, are custom errors enabled
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
return;
// Check if custom exception, if so get response code
if (filterContext.Exception is CustomException)
responseCode = (int)((CustomException)filterContext.Exception).Code;
// Log exception
string id = Logging.Write(LogType.Error, new
{
ResponseCode = responseCode,
Exception = new
{
Message = filterContext.Exception.Message,
Data = filterContext.Exception.Data,
Source = filterContext.Exception.Source,
StackTrace = filterContext.Exception.StackTrace,
InnerException = filterContext.Exception.InnerException != null ? new
{
Message = filterContext.Exception.InnerException.Message,
Data = filterContext.Exception.InnerException.Data,
Source = filterContext.Exception.InnerException.Source,
StackTrace = filterContext.Exception.InnerException.StackTrace
} : null
},
Context = filterContext.Controller != null ? new
{
RouteData = filterContext.Controller.ControllerContext.RouteData,
QueryString = filterContext.Controller.ControllerContext.HttpContext.Request.Url.Query,
FormParams = filterContext.Controller.ControllerContext.HttpContext.Request.Form != null ? string.Join(";#", filterContext.Controller.ControllerContext.HttpContext.Request.Form.AllKeys.Select(key => key + ":" + filterContext.Controller.ControllerContext.HttpContext.Request.Form[key])) : string.Empty,
Model = (filterContext.Controller is Controller) ? ((Controller)filterContext.Controller).ModelState : null,
ViewBag = filterContext.Controller.ViewBag,
ViewData = filterContext.Controller.ViewData
} : null,
ActionResult = filterContext.Result != null ? filterContext.Result : null,
Referrer = filterContext.HttpContext.Request.UrlReferrer != null ? filterContext.HttpContext.Request.UrlReferrer : null
}).Result;
// Mark exception as handled and return
filterContext.ExceptionHandled = true;
// Test for Ajax call
if (IsAjax(filterContext))
{
// Construct appropriate Json response
filterContext.Result = new JsonResult()
{
Data = new
{
code = responseCode,
id = id,
message = filterContext.Exception.Message
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
var result = new ViewResult();
result.ViewName = "_CustomError";
result.ViewBag.CorrelationId = id;
filterContext.Result = result;
}
}
/// <summary>
/// Determine if the request is from an Ajax call
/// </summary>
/// <param name="filterContext">The request context</param>
/// <returns>True or false for an Ajax call</returns>
private bool IsAjax(ExceptionContext filterContext)
{
return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
}
}
I have a CustomException where I check for a application-set response code.
Additionally, I take the querystring, form data, and the model so that I can see the values passed before and after the model binder.
If its and Ajax call, I return a Json-formatted response. Otherwise, I return a custom error page.
List<string> values = new List<string>();
values.AddRange(all.AllKeys.SelectMany(all.GetValues).Where(getValues => getValues != null));
string Values = string.Join(",", values.ToArray());
You can try something like the above.