I'm using the System.Linq.Dynamic library found here, which is simply an upload of Microsoft's library to be accessible via NuGet: https://github.com/kahanu/System.Linq.Dynamic
In my code, I have this function that gets a list of objects from a database that match a certain property. It needed to be as flexible as possible, so the parameters consist of three strings;
One for the "order by" statement
One for the property to match's name
One for the expected property's value
Here's the line of code that's giving me trouble:
public IQueryable<T> GetByProperty(string propertyName, string propertyValue,
string orderStatement)
{
return _context.Set<T>()
.OrderBy(orderStatement)
.Where(propertyName + " = " + propertyValue);
}
Here are the possible scenarios;
propertyValue contains only numbers: the query works perfectly.
propertyValue starts with numbers but has letters in it: the following error appears: Operator '=' incompatible with operand types 'String' and 'Int32'
propertyValue is anything else: the following error appears: No property or field '[the first part of the "propertyValue string, up until it meets an empty space, a "-" or some other specific characters]' exists in type '[Class name of <T>]'
I've tried using single quotes to surround my string, but I then get the error: 'Character literal must contain exactly one character'
I've also desperately tried to add ".ToString()" at the end to try and trick something into working, but I found the error: Digit expected.
Is there another way to use the "Where" clause, in Linq and Dynamic Linq, that would support the flexibility I'm trying to have using this structure?
You need to know the type of the property and format the value accordingly. If it is a string, enclose it in double quotes. i.e. name = "John" but age = 20.
It does not depend whether the value looks like a number or not.
If the type of the property is a number type then the value must be a number as well and not be enclosed in quotes.
If the type of the property is a string then the value must be enclosed in double quotes, even if the value is a number (e.g. code = "3").
Related
I use a library which provides a custom fluent implementation for string.Format. The idea is to replace the common format construct with one that reads in a more natural way like this:
// From this
string.Format("some format string with {0} parameter", 1);
string.Format(SomeConstant, "abc");
// To this
"some format string with {0} parameter".Format(1);
SomeConstant.Format("abc");
I was trying to setup a simple structural find and replace pattern in Resharper to help me deal with those inside my code base. I noticed that if I set the format string parameter as an Argument Placeholder matching exactly one argument and the list of arguments uses entity objects (like a Person object), the previous example would turn into:
// Note that this is the System.String class and not the original format string
String.Format(someEntity);
If the entity is first converted to a string, then it matches properly and keeps the format string as I would expect.
SomeConstant.Format(someEntity.ToString());
I had to use an Expression Placeholder with an expression type of System.String to properly match the first parameter.
Is this a bug or is there something that I am not understanding in this behavior? Why would the type of the second argument influence the match of the first argument? I have a feeling that I might be misunderstanding how Argument Placeholders are working...
NB: Using Resharper 9.0 Update 1
EDIT: As requested, here is the search pattern details:
Search Pattern: String.Format($format$, $args$)
Replace Pattern: $format$.Format($args)
format: Argument Placeholder, matching exactly one argument
args: Argument Placeholder, matching at least one argument
I am reading a legacy framework written in C#, there is a constant string defined as following:
private const string NAVBAR_PANEL_TEMPLATE =
".//*[#id='navbar']//*[contains(#class, 'platform-nav-{0}')]";
This string is to be used for element-searching by xpath. To my understanding, it can be translated as: "looking for elements whose ids are equal to 'navbar', under those matching elements, looking for elements whose class contains 'platform-nav-{0}'".
I am really confused by the last {0}, what does it represent?
It is likely not part of the XPath expression. The code is likely passing NAVBAR_PANEL_TEMPLATE to String.Format() and substituting a value in place of {0}.
if((string)row["ProductID"].ToString() == txtBarcode.Text)
I want to search a row if the value of the txtbox is the same as my datatable but i have an error.. it says that Possible unintended reference comparison; to get a value comparison, cast the left hand side to string. i just use .ToString() and Convert.ToString() but still have that error.
Your .ToString() is converting the row value to a string, so you don't also need to cast it on the left with (string)
Ie. if(row["ProductID"].ToString() == txtBarcode.Text)
Personally, I'd stare clear of using == operator with anything but ints, chars and whether this instance is that instance.
A better way of comparing strings is to use string.Equals(string) string.contains(string) or string.indexOf(string)
Note : if you are comparing with TextBox value then it is better to trim the values before comparing to remove the whitespaces using Trim() method.
Solution 1: if you want to find the excat match then you need to use Equals() method.
if(row["ProductID"].ToString().Equals(txtBarcode.Text.Trim())
{
/* do something*/
}
Solution 2: if you want to find the part of the string then you can use String.Contains() method as below:
if(row["ProductID"].ToString().Contains(txtBarcode.Text.Trim())
{
/* do something*/
}
You need to do one of the above. Either do a cast (string)row["ProductId"] or Convert.ToString(row["ProductId"]) for converting the value to string. But casting using (string)row["ProductId"] is likely to throw InvalidCastException. So may be ToString() would be better.
I'm using reflection to invoke methods and access properties in C#. The names of these properties and and methods have already been declared (in strings from a certain data source), but not in a 'method friendly' manner.
For example, a particular object has the property "HasAModifiedShortStyle"
At runtime I don't know this. I know I'm looking for a property described with "has a modified ShortStyle".
So the easy thing is to convert to TitleCase using
System.Globalization.CultureInfo.CurrentCulture.TextInfo)
and replace " " with "".
This works fine, but the TextInfo.ToTitleCase() changes "ShortStyle" to "Shortstyle". That lower case 's' causes me to not find the propertyName.
For reference, I'm accessing the property with
currentObjectValue.GetType().GetProperty(propertyName);
Is there an easy way to convert to TitleCase while preserving the in-word capitilization?
How about this approach?
currentObjectValue.GetType().GetProperties().FirstOrDefault(propInfo => propInfo.Name.Equals("Shortstyle", StringComparison.InvariantCultureIgnoreCase));
Just use this for every word in your description:
yourString[0].ToString().ToUpper() + yourString.Substring(1)
This will split the description string into individual words, capitalize the first letter, and then join them back into a single string:
string s = "has a modified ShortStyle";
propName = string.Join(string.Empty,
(from word in s.Split(' ')
select word.Substring(0, 1).ToUpper() + word.Substring(1)).ToArray());
I am trying to select all nodes with attribute equal to something, I got the error in title.
My Xpath string looks like //#[id=****], anyone know what's wrong?
Your XPath expression probably should be:
//*[#id='something']
Which means match all elements whose id attributes are equal to something, anywhere in the document.
EDIT: If you want the id attribute nodes themselves and not their parent elements, you can use:
//*[#id='something']/#id
Or even better, as #Dimitre Novatchev suggested:
//#id[. = 'something']
I am trying to select all nodes with
attribute equal to something, I got
the error in title.
My Xpath string looks like
//#[id=****], anyone know what's
wrong?
A lot of issues with this expression:
.1. //#[some-condition] The predicate can only be applied to selected nodes, but //# doesn't select any node. # is an abbreviation for attribute:: and this is an unfinished node-test. It is missing the node-type or node-name here.
What would be correct is: //#*[some-condition] or //#attrName[some-condition]
.2. id=**** is syntactically invalid, unless ** is a valid XPath expression itself. My guess is that you want to get all attributes with value equal to some known, literal value. In any such case the syntax to use is id='someLiteral -- do note the single quotes (they can also be double quotes) surrounding the literal value.
Solution:
//*[#id='something']
This selects all elements in the XML document that have attribute id with value 'something'.
//#id[. = 'something']
This selects all attributes named id in the XML document, whose value is 'something'.
//#*[. = 'something']
This selects all attributes in the XML document (regardless of their name), whose value is 'something'.