If a field contains null then entire concatenate result is null - c#

I am trying to concatenate for a label. If a field contains null then entire concatenate result is null.
[HttpGet]
public ActionResult PMAByPC(string PartnerCode)
{
var result = (from N in _POSContext.PMAs
where (N.PartnerCode == PartnerCode)
select new
{
label = N.Address1 + " | " + N.Address2 + " | " + N.City,
id = N.ID
});
return Json(result);
}
Here, if data is not present in of the fields, label becomes null.
I tried with
select new { label = N.Address1 ?? "?" + " | " + N.Address2 ?? "?" + " | " + N.City ?? "?", id = N.ID }
then it takes only N.Address1 value and ignores the rest of the fields.

Looks like this is a standard SQL string concatenation behavior (the same happens with SqlServer database).
If you want to evaluate the concatenation server side (database), you need to convert null to empty string "" (or something else) using the ?? operator. Similar to your attempt, but you've missed the C# operator precedence. The way you wrote it is equivalent of
N.Address1 ??
(
("?" + " | " + N.Address2) ??
(
("?" + " | " + N.City) ?? "?"
)
)
which is not what was the intent.
You can avoid such issues by enclosing similar conversions with brackets:
select new
{
label = (N.Address1 ?? "?") + " | " + (N.Address2 ?? "?") + " | " + (N.City ?? "?"),
id = N.ID,
}

This is the standard compliant and reasonable behavior: if you concatenate a string with an unknown string, the result is unknown.
Use the coalesce function for that:
coalesce(col1, '') || coalesce(col2, '')

Related

Passing whole function as lambda expression to LINQ

I've getting auctions from my database as:
var auctions = from o in db.auctions select o;
I'd like to pass this function as lambda expression in .Where clause of my linq to filter my auctions result:
private bool wordsHasProductName(auction a, string[] words)
{
if (!a.product_name.Contains(' ')) // Auction product name is single word - check if
{
if (words.Length > 1) return false; // array is passed, single word is searching
else return a.product_name.Contains(words[0]); // check if product name consists passed string
}
else // Auction product name has more words check if passed string is partially in this product name
{
string[] productName = a.product_name.Split(' ');
var list = new List<string>(words);
foreach (string item in productName)
{
if (list.Contains(item)) list.Remove(item);
}
return list.Count == 0;
}
}
I'm calling it in my code, and while debugging there's no error at this line, here's place where I call .Where() clause in linq:
string[] words = searchName.Split(' ');
auctions = auctions.Where((a) => wordsHasProductName(a, words));
But at the end at return statement I'm getting exception error:
return View(auctions.ToPagedList(pageNumber, pageSize));
Error code:
An exception of type 'System.NotSupportedException' occurred in
EntityFramework.SqlServer.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method
'Boolean wordsHasProductName(IEP_Projekat.Models.auction,
System.String[])' method, and this method cannot be translated into a
store expression.
How could I succeed sending full bool function as lambda expression in my linq .Where()?
As others already mentioned, method calls cannot be used in LINQ to Entities because they cannot be translated to SQL. So the only possible way would be if you can rewrite the method as compatible expression. And here comes the other problem - you are using string.Split method which is not supported.
So you are out of luck. Or may be not. Here is the trick. Instead of splitting the product_name and checking if it contains every word in words, you can use the following (IMO equivalent) criteria:
words.All(word => (" " + product_name + " ").Contains(" " + word + " "))
Enclosing both product_name and word with space allows you to match the whole word at the beginning, middle or at the end of the target string. And it uses only constructs that are supported by the EF.
Putting it all together. The function would be like this:
private static Expression<Func<auction, bool>> wordsHasProductName(string[] words)
{
if (words.Length == 1)
{
var word = words[0]; // Avoid ArrayIndex not supported
return a => !a.product_name.Contains(" ") && a.product_name.Contains(word);
}
else
{
return a => words.All(word => (" " + a.product_name + " ").Contains(" " + word + " "));
}
}
and the usage:
string[] words = searchName.Split(' ');
auctions = auctions.Where(wordsHasProductName(words));
However the above implementation does not produce very good SQL query, especially for more than one word. A much better SQL is produced if rewriting it by building the predicate expression manually:
private static Expression<Func<auction, bool>> wordsHasProductName(string[] words)
{
Expression<Func<auction, string>> product_name;
Expression condition;
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
if (words.Length == 1)
{
// a => !a.product_name.Contains(" ") && a.product_name.Contains(words[0])
product_name = a => a.product_name;
condition = Expression.AndAlso(
Expression.Not(Expression.Call(product_name.Body, containsMethod, Expression.Constant(" "))),
Expression.Call(product_name.Body, containsMethod, Expression.Constant(words[0])));
}
else
{
// a => (" " + a.product_name + " ").Contains(" " + words[0] + " ")
// && (" " + a.product_name + " ").Contains(" " + words[1] + " ")
// ...
// && (" " + a.product_name + " ").Contains(" " + words[N-1] + " ")
product_name = a => " " + a.product_name + " ";
condition = words
.Select(word => Expression.Call(product_name.Body, containsMethod, Expression.Constant(" " + word + " ")))
.Aggregate<Expression>(Expression.AndAlso);
}
return Expression.Lambda<Func<auction, bool>>(condition, product_name.Parameters);
}
Welcome to the world of EF and expressions :)
You can't pass this complex C# logic as an Expression Tree that can interpreted by the EF provider and the hardest part for the provider is transforming it into SQL statements.
So, your option is to create a stored procedure where you pass in the required parameters, then you write the logic using pure SQL. Then, you map your SP to EF and call it to return the list of objects you want.

How to get same functionality as ISNULL in LINQ query

I have been trying to find a solution for this since part few hours and I feel like my brain is about to help. I have the below LINQ query.
DropDownListItem item = (
from c in context.Practitioners
where c.PractitionerID == id
select new DropDownListItem
{
Id = c.PractitionerID,
DisplayValue = c.FirstName + " " + c.MiddleName + " " + c.LastName,
IsActive = c.IsActive,
DisplayOrder = c.PractitionerID,
CreatedById = new Guid("COFFEEOO-LOVE-LIFE-LOVE-C0FFEEC0FFEE"),
CreatedDate = c.CreatedDate,
}).FirstOrDefault() ?? new DropDownListItem();
response.Data = item;
There are instaces when c.MiddleName could be null. How Can I handle it in this query so that if c.MiddleName is null I can just assign a blank "" string to it ?
Here's what I tried already which did not work out.
- Created extension to check IsNullOrEmpty. I found out this does not work on LINQ queries.
- tried converting c.Middle to string by doing something like c.MiddleName.ToString() which did not work for LINQ query either.
Please give me more more direction as to which I should move toward. Thanks!
You can check for nulls and empty strings instead of using any methods that LINQ to Entities does not understand (Trim will be translated to SQL):
DisplayValue = c.FirstName + " " + ((c.MiddleName == null || c.MiddleName.Trim() == string.Empty) ? string.Empty : (c.MiddleName + " ")) + c.LastName,
I'm a bit confused about your question. You are making a string, so even if c.MiddleName is null it should be interpreted as an empty string.
You can also try this:
DisplayValue = (c.MiddleName != null) ?
c.FirstName + " " + c.MiddleName + " " + c.LastName :
c.FirstName + " " + c.LastName,
But pretty much all other answers are very similar.
As a note, you are missing brackets behind select new DropDownListItem, so that might be problem.
I'll assume what you mean by c.MiddleName is empty is that c.MiddleName is null (because if it's an empty string you question makes no sense :p).
If it is indeed the case try writing c.MiddleName ?? ""
This means that if the left part of ?? is null the use the right part of the expression
See https://msdn.microsoft.com/en-us/library/ms173224.aspx for more documentation
And you would have to change your code in this fashion :
DropDownListItem item = (
from c in context.Practitioners
where c.PractitionerID == id
select new DropDownListItem
{
Id = c.PractitionerID,
DisplayValue = (c.FirstName ?? "") + " " + (c.MiddleName ?? "") + " " + (c.LastName ?? ""),
IsActive = c.IsActive,
DisplayOrder = c.PractitionerID,
CreatedById = new Guid("COFFEEOO-LOVE-LIFE-LOVE-C0FFEEC0FFEE"),
CreatedDate = c.CreatedDate,
}).FirstOrDefault() ?? new DropDownListItem();
response.Data = item;
To be noted that the ?? operator have one of the lowest priorities in C#.
Check the operators priority in C# here https://msdn.microsoft.com/en-us/library/6a71f45d.aspx
try this
DisplayValue = (c.FirstName?? string.Empty) + " " + (c.MiddleName ?? string.Empty) + " " + (c.LastName?? string.Empty)

What is the replacement Sql Char(13) and isnull in Entity Framework?

I am new to Entity framework, Can any body tell me how to write the following query into Entity framework.
select column1 + char(13) +isnull(column2,space(1))+char(13)+isnull(column3,space(1))+char(13)+isnull(column4,space(1)) +char(13)+isnull(olumn5,space(1)) as FADRS
FROM table
Convert the above query into Entity Framework.
By using Jon answer i get the answer. Know my problem is how to use iqueryable
IQuer<string> Madr = from b in context.table
where b.column1 == txtaddrss.Text
select new
{FADR = b.column2 + '\r' +
(b.column3 ?? " ") + '\r' +
(b.column4 ?? " ") + '\r' +
(b.column5 ?? " ") + '\r' +
(b.column6 ?? " ")};
foreach(string something in Madr)
{
MessageBox.Show(something);
}
i am getting error conversion failed because of anonymous type
char(13) just does the equivalent (though more limited) of (char)13 in C#, which would just return '\r'.
Hence you would either use '\r' or "\r".
isnull(x, y)just does the equivalent of x ?? y in C#.
So you would use something like:
var query = from item in TableSource select
item.column1 + '\r' +
(item.column2 ?? " ") + '\r' +
(item.column3 ?? " ") + '\r' +
(item.column4 ?? " ") + '\r' +
(item.column5 ?? " ");
TableSource is whatever way you are getting a reference to the table (context.Table or whatever).
query will be an IQueryable<string> returning the relevant strings when invoked. If you really want the FADRS name from your example then the following will instead of strings return anonymous objects with a FADRS property:
var query = from item in TableSource select
new {FADRS = item.column1 + '\r' +
(item.column2 ?? " ") + '\r' +
(item.column3 ?? " ") + '\r' +
(item.column4 ?? " ") + '\r' +
(item.column5 ?? " ")};
Edit:
The first example above can be used as:
foreach(string something in query)
MessageBox.Show(something);
The second example as:
foreach(var something in query)
MessageBox.Show(something.FADR);
With the first var is optional shorthand, with the second you must use var as the types involved are anonymous, and hence var is the only way to name the type (by not naming it at all).
Given no further context I'd say sonething like this:
var query = from obj in context.table
select new {
FADR = obj.column1 + "\r" +
obj.column2 ?? " " + "\r" +
obj.column3 ?? " " + "\r" +
obj.column4 ?? " " + "\r" +
obj.column5 ?? " " + "\r" };

NullReferenceException in string.IsNullOrWhiteSpace() and string.IsNullOrEmpty()

I'm checking the cell values of cells of a column that might or not be empty/null so I needed something to avoid a NullReferenceException.
How do I do that since even with the IsNullOrWhiteSpace() and IsNullOrEmpty() I get that exception somehow.
Here's part of the code I'm using:
s = "Total = " + dataGridView1.Rows[0].Cells.Count +
"0 = " + dataGridView1.Rows[0].Cells[0].Value.ToString() +
"/n 1 = " + dataGridView1.Rows[0].Cells[1].Value.ToString() +
"/n 2= " + dataGridView1.Rows[0].Cells[2].Value.ToString() +
"/n 3 = " + dataGridView1.Rows[0].Cells[3].Value.ToString() +
"/n 4= " + dataGridView1.Rows[0].Cells[4].Value.ToString() +
"/n 5 = " + dataGridView1.Rows[0].Cells[5].Value.ToString() +
"/n 6= " + dataGridView1.Rows[0].Cells[6].Value.ToString() +
"/n 7 = " + dataGridView1.Rows[0].Cells[7].Value.ToString();
if (string.IsNullOrEmpty(dataGridView1.Rows[0].Cells[8].Value.ToString()))
{
}
else
{
s += "/n 8 = " + dataGridView1.Rows[0].Cells[8].Value.ToString();
}
I've tried those methods I've tried putting it ==null, I've tried !=null. What else is there or what am I doing wrong exactly and how do I do it right?
the are a lot of places you code could throw that exception ..
dataGridView1.Rows[0] //here
.Cells[0] //here
.Value //and here
.ToString()
I belive you don't need the ToString() just type:
"... "+ dataGridView1.Rows[0].Cells[0].Value
in your ifstatement do this:
if (string.IsNullOrEmpty(dataGridView1.Rows[0].Cells[8].Value as string))
Many people don't understand how to diagnose a NullReferenceException. Consider the following:
dataGridView1.Rows[0].Cells[3].Value.ToString()
Many parts of this could be null. It's the same thing as
var a = dataGridView1.Rows;
var b = a[0];
var c = b.Cells;
var d = c[3];
var e = d.Value;
var f = e.ToString();
If a is null, then a[0] will throw a NullReferenceException. If b is null, then b.Cells will throw a NullReferenceException, etc.
You simply have to figure out which of these is null in your particular situation. The simplest way is to use the debugger. Set a breakpoint before the line that throws the exception. Then hover the mouse over various parts of the expression to see which are null, or use the "Watch" window to enter parts of the expression.
When you find a null, you can stop looking for your NullReferenceException.
You can add an extra line of code to check and handle the null case.
var value = dataGridView1.Rows[0].Cells[0].Value;
string s = (value == null ? string.Empty : value.ToString());
If value is null, then ToString() will not be evaluated and the program cannot throw NullReferenceException.
I think in dataGridView1.Rows[0].Cells[8].Value.ToString() you will get a NullReferenceException if the Value is null. So you should check for dataGridView1.Rows[0].Cells[8].Value != null and then you can convert it to a string

Concatenate NULL and string in Linq to entities query

This query actually works but returns new objects with ClientName set to null where FirstName or Lastname is null (any one of the two). How can I get around that? I would like to have an empty string instead of null in those rows.
var clients =
from client in _repository.GetAll()
where (client.Firstname.StartsWith(query) || client.Lastname.StartsWith(query))
select new
{
ClientName = (client.Firstname + " " + client.Lastname).Trim(),
client.Firstname,
client.Lastname,
client.Address1,
client.Address2,
client.client_id,
client.PrettyId,
client.PostCode.postalcode,
client.PostCode.postname
};
((client.Firstname ?? "") + " " + (client.Lastname ?? "")).Trim();

Categories

Resources