Inline if Statement not working - c#

For some reason, when I add the ternary if statement to this bit of code, a NullPointerException is thrown. I'm not sure quite why...any ideas? This is the method for jqGrid - returning the Json data.
var gridModel = from entity in vendorList.AsQueryable()
select new
{
VendorId = "<a href='/Admin/DetailsPlan/" + entity.VendorId + "'><img src='/Images/next_icon_sm.png' class='icon' alt='View Vendor' /></a>",
VendorNm = entity.VendorNm,
Phone = (entity.Phone.Length < 5) ? String.Format("{0:(###) ###-####}", Convert.ToInt64(entity.Phone)) : entity.Phone,
City = entity.City,
State = entity.LkState.StateAbbr
};
Can you not have a ternary if statement in that location?

var gridModel = from entity in vendorList.AsQueryable()
let unformattedPhone = entity.Phone??string.Empty
select new
{
VendorId = "<a href='/Admin/DetailsPlan/" + entity.VendorId + "'><img src='/Images/next_icon_sm.png' class='icon' alt='View Vendor' /></a>",
VendorNm = entity.VendorNm,
Phone = (unformattedPhone.Length < 5) ? String.Format("{0:(###) ###-####}", Convert.ToInt64(unformattedPhone)) : unformattedPhone,
City = entity.City,
State = entity.LkState.StateAbbr
};
This may solve your problem.

One question, is entity.Phone null? If so, that would be the cause.
Side note: I have to say, that is an odd way of storing a phone number..
UPDATE
The problem is with the "entity.Phone.Length" part. If Phone is null, then you can't access it's length property... hence the error. So you need to add a null test. Something like:
Phone = ((entity.Phone != null) && (entity.Phone.Length < 5)) ? String.Format("{0:(###) ###-####}", Convert.ToInt64(entity.Phone)) : entity.Phone
That way, if it is null you are just emitting a null value.

Related

How can I express this nested loop in LINQ?

Background:
I have ASP.NET Core app. I'm trying to write server-side validation errors to the log.
If ASP.NET Core model validation detects any error in any field in the webform, then ModelState.IsValid is false.
Every field in the webform is listed in ModelState.Values
If a "Value" has one or more errors, then Value.Errors.Count > 0
I want to log a) the webform field name (the Value's "key") and b) each error message for that field.
I'd like to include all this information in a single line (i.e. a single C# "string").
Current code:
// LOG:
// 2022-10-24 09:37:29.0909|Error|ServiceMenu.Q255: The value '' is invalid.
// 2022-10-24 09:37:35.4096|Error|ServiceMenu.Q265: The value '' is invalid.
if (!ModelState.IsValid)
{
foreach (var k in ModelState.Keys)
{
var v = ModelState[k];
if (v.Errors.Count > 0)
{
string s = k + ": ";
for (int i=0; i < v.Errors.Count - 1; i++)
s += v.Errors[i].ErrorMessage + ", ";
s += v.Errors[v.Errors.Count - 1].ErrorMessage;
_logger.LogError(s);
}
}
return Page();
}
Sample output (two required fields, Q255 and 265, were blank):
2022-10-24 09:37:29.0909|Error|ServiceMenu.Q255: The value '' is invalid.
2022-10-24 09:37:35.4096|Error|ServiceMenu.Q265: The value '' is invalid.
Q: Can I simplify this nested loop with LINQ?
Update:
Thank you, everybody.
Evk and T.S. are both absolutely correct: "Don't think that using LINQ is always good." I don't - and their point is very well taken :)
Oliver Weichhold gave me the syntax I was looking for :)
Here's the code I finally wound up with:
// EXAMPLE LOG:
// 2022-10-24 13:24:10.5242|Error|ServiceMenu.Q255: The value '' is invalid.
// 2022-10-24 13:24:24.9692|Error|ServiceMenu.Q265: The value '' is invalid.
if (!ModelState.IsValid)
{
foreach (var k in ModelState.Keys)
{
var v = ModelState[k];
if (v.Errors.Count > 0)
{
string s = string.Join(", ", ModelState[k].Errors
.Select(x => x.ErrorMessage));
_logger.LogError(k + ": " + s);
}
}
...
if (!ModelState.IsValid)
{
var logMessage = string.Join("\n", ModelState.Keys
.Where(x => ModelState[x].Errors?.Count > 0)
.Select(x => $"{x}: " + string.Join(", ", ModelState[x].Errors.Select(y => y.ErrorMessage))));
_logger.LogError(logMessage);
}

How to make a bool insert a X in report when true

foreach (SalesInfo sales in this)
{
if (sales.Senior == true)
senX = "x";
if (sales.Veteran == true)
vetX = "x";
fileOut.WriteLine("{0:d4} {1,-25} {2,-14} {3,3} {4,3} {5,10:MM/dd/yyyy} {6,10:n} "
+ "{7,10:n} {8,8:n} {9,6:n} {10,10:n}",
sales.ID, sales.Name, sales.City, senX, vetX, sales.PurDate,
sales.ProductTotal, sales.DiscountTotal, sales.SalesTax, sales.ShippingCharge,
sales.InvoiceTotal);
}
So my problem is when the data member for Senior or Veteran is true I need to insert a X into my report. This inst working so I wondered if anyone knew of a better way?
You have to set senX and vetX back to "" after writing the line, so it's empty for the new iteration. Otherwise you'll get exes throughout the report, regardless of the value of the boolean.
Another solution would be to use (sales.Senior?"X":"") as an expression in the WriteLine statement, so you don't need the variables at all.
foreach (SalesInfo sales in this)
{
senX = sales.Senior ? "x" : "";
vetX = sales.Veteran ? "x" : "";
fileOut.WriteLine("{0:d4} {1,-25} {2,-14} {3,3} {4,3} {5,10:MM/dd/yyyy} {6,10:n} "
+ "{7,10:n} {8,8:n} {9,6:n} {10,10:n}",
sales.ID, sales.Name, sales.City, senX, vetX, sales.PurDate,
sales.ProductTotal, sales.DiscountTotal, sales.SalesTax, sales.ShippingCharge,
sales.InvoiceTotal);
}
If you use the ternary operator (x ? y : z) in your assignments, it will take care of assigning the "x" and clearing the value to "" each loop iteration.
Try to add in the characters "{" and "}"!
if (sales.Senior == true)
{
senX = "x";
}
if (sales.Veteran == true)
{
vetX = "x";
}

Advice on building graphQL queries in c#

I am working on a data migration project - API to API.
The destination API is graphQL, we have a number of objects to push into the destination and the shapes vary so I am looking for some advice on how best to dynamically build mutations/queries specifically in c#.
Currently we are just using templates and using find/replace routines to inject values. While this approach does work as the shapes of the data vary this becomes evermore complex and inelegant.
I am looking for any advice/pointers from anyone who have may have had a similar scenario or knows of any libraries I should look at.
Update - 13/02/2018
I have since updated this monstrosity to cater for nested sub selections and GraphQl enums so if anyone is interested here it is in GitHub
Orignal answer
I've got the same requirement. Couldn't find anything out there so I've come up with this very inelegant solution. It works for my scenarios so I'll post it here for anyone else looking for a solution.
public static class GraphQlObjectParser
{
public static string Parse(string queryType, string queryName, string[] subSelection, object #object = null, string objectTypeName = null)
{
var query = queryType + "{" + queryName;
if (#object != null)
{
query += "(";
if (objectTypeName != null)
{
query += objectTypeName + ":" + "{";
}
var queryData = string.Empty;
foreach (var propertyInfo in #object.GetType().GetProperties())
{
var value = propertyInfo.GetValue(#object);
if (value != null)
{
var type = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
var valueQuotes = type == typeof(string) ? "\"" : string.Empty;
var queryPart = char.ToLowerInvariant(propertyInfo.Name[0]) + propertyInfo.Name.Substring(1) + ":" + valueQuotes + value + valueQuotes;
queryData += queryData.Length > 0 ? "," + queryPart : queryPart;
}
}
query += (objectTypeName != null ? queryData + "}" : queryData) + ")";
}
if (subSelection.Length > 0)
{
query += subSelection.Aggregate("{", (current, s) => current + (current.Length > 1 ? "," + s : s)) + "}";
}
query += "}";
return query;
}
}
This works for both queries and mutations. Examples of usage are:
var query = GraphQlObjectParser.Parse("query", "users", new[] { "id", "name" });
will give you
query{users{id,name}}
or
var query = GraphQlObjectParser.Parse("query", "user", new[] { "id", "name" }, new User { Id = 1 });
will give you
query{user(id:1){id,name}}
or
var query = GraphQlObjectParser.Parse("mutation", "user", new[] { "id", "name" }, new User { Id = 1, Name = "John" }, "data");
will give you
mutation{user(data:{id:1,name:"John"}){id,name}}
It'll work with enums which is why I needed this solution in the first place. You can pass in a sub selection without the object or the object without an object type name. I've tried to cover as many bases as possible although I've not yet catered for sub selection of a sub selection. I'll update here if/when I code this one.
Hope it helps someone.
There is a cool library that helps you with building your GraphQL queries in the fluent API style. https://charlesdevandiere.github.io/graphql-query-builder-dotnet/

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

Object Reference error in LINQ

I had applied the following code :
var country = from cnty in this.GetAll<CompanyDefinition>().ToList()
where cnty.IsImported = true
select new {
CompanyDefinitionID = cnty.CompanyDefinitionID
, CompanyDefinitionName = cnty.Company.CompanyName + "(" + cnty.Country.CountryCode + "," + cnty.NaicsCode.NaicsCode1 + ")"
};
And I am getting Object Reference error. Its pointing to "select new". Whats the correct way?
The problem is Company, Country or NaicsCode is null, you would need to check this before attempting to access their properties. For example, you could re-write your query as:
var country = from cnty in this.GetAll<CompanyDefinition>()
where cnty.IsImported && cnty.Company != null && cnty.Country != null && cnty.NaicsCode != null
select new {
...
}
If you are employing lazy loading, then using ToList() method is not proper. After calling ToList(), IQueryable<> object is materialized to IEnumerable<>; thus database is not queried for Company or Country references. Try removing ToList() function.

Categories