How to concat strings in LINQ while properly dealing with NULL values - linq

I'd like an elegant way to concatenate several columns together using LINQ, but using the + operator or concat() when any of the columns are NULL results in NULL for the value after concatenation.
Is there anything similar to concat() that handles NULL differently, or am I thinking about this in the incorrect way?
Any help is appreciated!
Here is the code I am using:
List<CustomObject> objects = (
from obj in ObjectTable
where obj.Id == Id
select new CustomObject()
{
EnteredBy = obj.EnteredBy,
EntryDate = obj.EntryDate,
WorknoteText =
obj.VchWorkNote1 +
obj.VchWorkNote2 +
obj.VchWorkNote3 +
obj.VchWorkNote4 +
obj.VchWorkNote5 +
obj.VchWorkNote6 +
obj.VchWorkNote7 +
obj.VchWorkNote8 +
obj.VchWorkNote9 +
obj.VchWorkNote10 +
obj.VchWorkNote11 +
obj.VchWorkNote12 +
obj.VchWorkNote13 +
obj.VchWorkNote14 +
obj.VchWorkNote15 +
obj.VchWorkNote16 +
obj.VchWorkNote17 +
obj.VchWorkNote18 +
obj.VchWorkNote19 +
obj.VchWorkNote20
}).ToList();

One option is to use the null coalescing operator:
List<CustomObject> objects = (from o in ObjectTable
where o.Id == Id
select new CustomObject(){
EnteredBy = o.EnteredBy,
EntryDate = o.EntryDate,
WorknoteText =
(o.VchWorkNote1 ?? "") +
(o.VchWorkNote2 ?? "") +
(o.VchWorkNote3 ?? "") +
(o.VchWorkNote4 ?? "") +
...
(o.VchWorkNote20 ?? "")
}).ToList();
Hopefully the generated SQL will use an appropriate translation.

You can use the ?? operator this way :
...
(object.VchWorkNote5 ?? "") +
(object.VchWorkNote6 ?? "") +
(object.VchWorkNote7 ?? "") +
...

How about (object.VchWorkNote1 ?? "") +.....

Can you add a new column to your database? Something like "Keywords" or "FullText"
Define it to have a calculation, that calculation is basically "ISNULL(<Field1>, '') + ISNULL(<Field2>, '')" etc.
Make sure to mark it as persisted, so it doesn't have to calculate each time.
Then you just need to pull down that one field from your table.

there's probably a cleaner way, but first thing that comes to mind would be a quick null to zero length string conversion:
List<CustomObject> objects = (from object in ObjectTable
where object.Id == Id
select new CustomObject(){
EnteredBy = object.EnteredBy,
EntryDate = object.EntryDate,
WorknoteText =
object.VchWorkNote1 ?? "" +
object.VchWorkNote2 ?? "" +
object.VchWorkNote3 ?? "" +
object.VchWorkNote4 ?? "" +
object.VchWorkNote5 ?? "" +
object.VchWorkNote6 ?? "" +
object.VchWorkNote7 ?? "" +
object.VchWorkNote8 ?? "" +
object.VchWorkNote9 ?? "" +
object.VchWorkNote10 ?? "" +
object.VchWorkNote11 ?? "" +
object.VchWorkNote12 ?? "" +
object.VchWorkNote13 ?? "" +
object.VchWorkNote14 ?? "" +
object.VchWorkNote15 ?? "" +
object.VchWorkNote16 ?? "" +
object.VchWorkNote17 ?? "" +
object.VchWorkNote18 ?? "" +
object.VchWorkNote19 ?? "" +
object.VchWorkNote20 ?? ""
}).ToList();

Related

Failed to get #Query Result

Hello I'm trying to read tables related with ManyToOne , i get the result when i execute the query in Navicat :
but when i try to display data in the front with angular i failed i get only the main tables
this is the query :
//like this
#Query(value = "SELECT\n" +
"\tnotification.idnotif,\n" +
"\tnotification.message,\n" +
"\tnotification.\"state\",\n" +
"\tnotification.title,\n" +
"\tnotification.\"customData\",\n" +
"\tnotification.\"date\",\n" +
"\tnotification.receiver,\n" +
"\tnotification.sender,\n" +
"\tnotification.\"type\",\n" +
"\thospital.\"name\",\n" +
"\thospital.\"siretNumber\",\n" +
"\tusers.firstname,\n" +
"\tusers.\"isActive\" \n" +
"FROM\n" +
"\tnotification\n" +
"\tINNER JOIN hospital ON notification.receiver = :reciver\n" +
"\tINNER JOIN users ON notification.sender = :sender",nativeQuery = true)
List<Notification> findNotificationCustomQuery(#Param("reciver") Long reciver,#Param("sender") Long sender);
please what can i do to resolve this problem !
You are doing inner join in the native query. Follow as below. Change the return type to Object[] from Notification.
#Query(value = "SELECT\n" +
"\tnotification.idnotif,\n" +
"\tnotification.message,\n" +
"\tnotification.\"state\",\n" +
"\tnotification.title,\n" +
"\tnotification.\"customData\",\n" +
"\tnotification.\"date\",\n" +
"\tnotification.receiver,\n" +
"\tnotification.sender,\n" +
"\tnotification.\"type\",\n" +
"\thospital.\"name\",\n" +
"\thospital.\"siretNumber\",\n" +
"\tusers.firstname,\n" +
"\tusers.\"isActive\" \n" +
"FROM\n" +
"\tnotification\n" +
"\tINNER JOIN hospital ON notification.receiver = :reciver\n" +
"\tINNER JOIN users ON notification.sender =
:sender",nativeQuery = true)
List<Object []> findNotificationCustomQuery(#Param("reciver")
Long reciver,#Param("sender") Long sender);
Then you have to loop the result as below and get the attributes.
for(Object[] obj : result){
String is = obj[0];
//Get like above
}

Searching for a range of dates in LINQ

I'm trying to do a search through a table via LINQ and Entity Framework CORE. I've got 2 text boxes startdate and enddate and a radio button set of 3 options created, modified and both.
This is the code I've produced based on Google searches and tutorials
switch(radCreatedModifiedBoth) {
case "b":
if (!String.IsNullOrEmpty(startDate)) {
if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(startDate + " 00:00:00") &&
ps.CreatedDate <= Convert.ToDateTime(endDate + " 23:59:59")
) || (
ps.ModifiedDate >= Convert.ToDateTime(startDate + " 00:00:00") &&
ps.ModifiedDate <= Convert.ToDateTime(endDate + " 23:59:59")
)
);
} else {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(startDate + " 00:00:00")
||
ps.ModifiedDate >= Convert.ToDateTime(startDate + " 00:00:00")
)
);
}
} else if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(endDate + " 23:59:59")
||
ps.ModifiedDate >= Convert.ToDateTime(endDate + " 23:59:59")
)
);
}
break;
case "c":
if (!String.IsNullOrEmpty(startDate)) {
if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(startDate + " 00:00:00") &&
ps.CreatedDate <= Convert.ToDateTime(endDate + " 23:59:59")
)
);
} else {
persons = persons.Where(ps => (
ps.CreatedDate >= Convert.ToDateTime(startDate + " 00:00:00")
)
);
}
} else if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps <= (
ps.CreatedDate >= Convert.ToDateTime(endDate + " 23:59:59")
)
);
}
break;
case "m":
if (!String.IsNullOrEmpty(startDate)) {
if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps => (
ps.ModifiedDate >= Convert.ToDateTime(startDate + " 00:00:00") &&
ps.ModifiedDate <= Convert.ToDateTime(endDate + " 23:59:59")
)
);
} else {
persons = persons.Where(ps => (
ps.ModifiedDate >= Convert.ToDateTime(startDate + " 00:00:00")
)
);
}
} else if (!String.IsNullOrEmpty(endDate)) {
persons = persons.Where(ps <= (
ps.ModifiedDate >= Convert.ToDateTime(endDate + " 23:59:59")
)
);
}
break;
}
This code works but seems massively inefficient, not to mention adding the start and end time into the date as a string like this
startDate + " 00:00:00"
endDate + " 23:59:59"
just seems wrong. Is this the prescribed method or can anyone suggest a more efficient method preferably getting rid of the " 00:00:00"/" 23:59:59"
Thanks
You can simplify by pushing the tests to SQL - the conditional operator will be translated to SQL CASE WHEN since they aren't simple constants. Note that I assumed you have the endDate tests backwards in your code sample. Also you have a lot of repeated sub-expressions I consolidated to variables. Since you are using EF Core, there isn't a better way to handle date only comparisons then what you are using. In EF you can use a DbFunction, but it still isn't as good as converting your dates to the appropriate date+time so that indices can be used.
var hasStartDate = !String.IsNullOrEmpty(startDate);
var dtStartDate = hasStartDate ? Convert.ToDateTime(startDate + " 00:00:00") : DateTime.MinValue;
var hasEndDate = !String.IsNullOrEmpty(endDate);
var dtEndDate = hasEndDate ? Convert.ToDateTime(endDate + " 23:59:59") : DateTime.MinValue;
var chkCreatedDate = (radCreatedModifiedBoth == "b" || radCreatedModifiedBoth == "c");
var chkModifiedDate = (radCreatedModifiedBoth == "b" || radCreatedModifiedBoth == "m");
persons = persons.Where(ps => (chkCreatedDate ? (hasStartDate ? ps.CreatedDate >= dtStartDate : true) && (hasEndDate ? ps.CreatedDate <= dtEndDate : true) : true)
||
(chkModifiedDate ? (hasEndDate ? ps.ModifiedDate >= dtStartDate : true) && (hasEndDate ? ps.ModifiedDate <= dtEndDate : true) : true)
);

MongoDB Native Query vs C# LINQ Performance

I am using the following two options, the Mongo C# driver seems to be taking more time. I'm using StopWatch to calculate the timings.
Case 1: Native Mongo QueryDocument (takes 0.0011 ms to return data)
string querytext = #"{schemas:{$elemMatch:{name: " + n + ",code : " + c + "} }},{schemas:{$elemMatch:{code :" + c1 + "}}}";
string printQueryname = "Query: " + querytext;
BsonDocument query1 = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(querytext);
QueryDocument queryDoc1 = new QueryDocument(query1);
var queryResponse = collection.FindAs<BsonDocument>(queryDoc1);
Case 2: Mongo C# Driver (takes more than 3.2 ms to return data)
Schema _result = new Schema();
_result = (from c in _coll.AsQueryable<Schema>()
where c.schemas.Any(s => s.code.Equals(c) && s.name.Equals(n) ) &&
c.schemas.Any(s => s.code.Equals(c1))
select c).FirstOrDefault();
Any thoughts ? Anything wrong here ?

Selecting values from IQueryable with IsNullOrWhitespace check

I am trying to do the following with a IQueryable expression:
(from Person p in s
select new
{
label = p.FirstName + " "
+ (string.IsNullOrWhiteSpace(p.MiddleName) ? p.MiddleName + " " : "")
+ p.LastName,
value = p.Id
}).ToList();
I am getting following error:
LINQ to Entities does not recognize the method 'Boolean
IsNullOrWhiteSpace(System.String)' method, and this method cannot be
translated into a store expression.
What is the solution for this?
String.IsNullOrWhitespace is a static function of the string object and cannot be used with Entity Framework queries, whereas p.FirstName.StartsWith("S") is a method of the entity property and can be used.
To answer your question you will have to roll your own inline. Try this:
(from Person p in s
select new
{
label = p.FirstName + " "
+ ((p.MiddleName != null && p.MiddleName != string.Empty) ? p.MiddleName + " " : "")
+ p.LastName,
value = p.Id
}).ToList();

Ajax/jQuery Timing Issue

I have a click function that does a jQuery/Ajax $.post to get data from a webservice when a span is clicked. When there is a Firebug break point set on the click function, everything works as expected (some new table tr's are appended to a table). When there is no break point set, nothing happens when you click the span. Firebug doesn't show any errors. I assume from other stackoverflow questions that this is a timing problem, but I don't know what to do about it. I have tried changing from a $.post to a $.ajax and setting async to false, but that didn't fix it. Here's the code for the click handler:
$('.rating_config').click(function(event){
event.preventDefault();
event.stopPropagation();
var that = $(this);
// calculate the name of the module based on the classes of the parent <tr>
var mytrclasses = $(this).parents('tr').attr('class');
var modulestart = mytrclasses.indexOf('module-');
var start = mytrclasses.indexOf('-', modulestart) + 1;
var stop = mytrclasses.indexOf(' ', start);
var mymodule = mytrclasses.substring(start, stop);
mymodule = mymodule.replace(/ /g, '+');
mymodule = mymodule.replace(/_/g, '+');
mymodule = encodeURI(mymodule);
// calculate the name of the property based on the classes of the parent <tr>
var propertystart = mytrclasses.indexOf('property-');
var propstart = mytrclasses.indexOf('-', propertystart) + 1;
var propstop = mytrclasses.indexOf(' ', propstart);
var myproperty = mytrclasses.substring(propstart, propstop);
myproperty = myproperty.replace(/ /g, '+');
myproperty = myproperty.replace(/_/g, '+');
myproperty = encodeURI(myproperty);
var parentspanid = $(this).attr('id');
// Remove the comparison rows if they are already present, otherwise generate them
if ($('.comparison_' + parentspanid).length != 0) {
$('.comparison_' + parentspanid).remove();
} else {
$.post('http://localhost/LearnPHP/webservice.php?user=user-0&q=comparison&level=property&module=' + mymodule + '&version_id=1.0&property=' + myproperty + '&format=xml', function(data) {
var data = $.xml2json(data);
for (var propnum in data.configuration.modules.module.properties.property) {
var prop = data.configuration.modules.module.properties.property[propnum];
console.log(JSON.stringify(prop));
prop.mod_or_config = 'config';
var item_id = mymodule + '?' + prop.property_name + '?' + prop.version_id + '?' + prop.value;
item_id = convertId(item_id);
prop.id = item_id;
//alert('prop.conformity = ' + prop.conformity);
// genRow(row, module, comparison, comparison_parentspanid)
var rowstring = genRow(prop, mymodule, true, parentspanid);
console.log('back from genRow. rowstring = ' + rowstring);
$(that).closest('tr').after(rowstring);
//$('tr#node-' + data[row].id + ' span#rating' + row.id).css('background', '-moz-linear-gradient(left, #ff0000 0%, #ff0000 ' + data[row].conformity + '%, #00ff00 ' + 100 - data[row].conformity + '%, #00ff00 100%');
var conformity_color = getConformityColor(prop.conformity);
$('tr#comparison_module_' + mymodule + '_setting_' + prop.id + ' span#module_' + mymodule + '_rating' + prop.id).css({'background':'-moz-linear-gradient(left, ' + conformity_color + ' 0%, ' + conformity_color + ' ' + prop.conformity + '%, #fffff0 ' + prop.conformity + '%, #fffff0 100%)'});
//$('tr#comparison-' + data[row].id + ' span#rating' + data[row].id).css('background','-webkit-linear-gradient(left, #00ff00 0%, #00ff00 ' + data[row].conformity + '%, #ff0000 ' + (100 - (data[row].conformity + 2)) + '%, #ff0000 100%)');
}
});
// Hide the Fix by mod column
hideFixedByModCol();
$('tr.comparison_' + parentspanid).each(function(i){
if (i % 2 == 0) {
$(that).addClass('comparison_even');
} else {
$(that).addClass('comparison_odd');
}
});
}
});
Any help would be greatly appreciated!
I suspect your data is coming back improperly formed. Enclose your code from the break on within try {} catch {} to see the error generated. Also it would be a good idea to add error processing to your ajax request.

Resources