I have the following query, sometimes ExpirationDate is null which blows up the query and the application crashes. If ExpirationDate is null I want to return "" for ExpirationDate. How do I put this if condition in LINQ?
List<PData> pressData =
(from press in dataContext.CPress
where press.ID.ToString() == this.PressID
select new PData
{
Heading = press.Heading,
Description = press.MetaDescription,
DatePublished = press.PublishDate.ToShortDateString(),
ExpirationDate = press.ExpirationDate.Value.ToShortDateString(),
Body = press.BodyContent,
CreatedBy=press.CreatedBy
}).ToList();
UPDATE :
Adding the code Jon suggested I get the following exception
Could not translate expression 'Table(CPress).Where(press =>
(press.PressID.ToString() =
Invoke(value(System.Func`1[System.String])))).Select(press
=> new PData() {Heading = press.Heading, Description =
press.MetaDescription, DatePublished =
press.PublishDate.ToShortDateString(),
ExpirationDate =
IIF((press.ExpirationDate = null), "",
press.ExpirationDate.Value.ToShortDateString()),
Body = press.BodyContent, ID =
press.PressID, CreatedBy =
press.CreatedBy})' into SQL and could
not treat it as a local expression.
Taking ExpirationDate out totally the exception goes away
I'd use:
ExpirationDate = press.ExpirationDate == null ? "":
press.ExpirationDate.Value.ToShortDateString()
EDIT: Having said that, it will only work around the immediate problem. I agree with Nelson's approach of keeping it as a DateTime? and performing the conversion at display time. Aside from anything else, that means you can apply the appropriate culture information etc for the user at that point.
I know it doesn't answer you question directly, but...
If possible, I would keep the date as DateTime?. Usually you want to format it (ToShortDateString(), etc.) whenever you display it, not before.
Edit: Similarly in where press.ID.ToString() == this.PressID: this.PressID would ideally match the type of press.ID. Really, the language is strongly-typed for a reason. If you make all your variables strings, it defeats the whole purpose.
Of course there are some unusual circumstances where you might have to do this and yours may be one of them, but I see no indication that is the case.
Personally I'd go for the option that #Jon Skeet has suggested, but an alternative if you don't like the syntax is to write an extension method and call that
public static string ToShortDateStringOrEmpty(this DateTime? dt)
{
if (dt == null)
return String.Empty;
else
return dt.ToShortDateString();
}
This has the advantage of being neater if you're doing a complex query (such as if the order isn't null, show me the sum of all the line items) and traversing a lot of objects.
Related
I have this error
Unable to create a constant value of type 'Controllers.Administrator'. Only primitive types or enumeration types are supported in this context.
I have a variable List<Administrator> result that is getting it's values from Database.SqlQuery<Administrator>.
Administrator class looks like this
public class Administrator
{
public string AdminName { get; set; }
public string Numer { get; set; }
}
Than I have something like this
var sheet = from k in Context.Admins.AsNoTracking()
select new Admin()
{
// some other variables
Numer = k.Numer,
AdminName = result.FirstOrDefault(a => a.Numer == k.Numer).AdminName ?? String.Empty
};
AdminName line is giving me the error, why can't it work like this?
I'm trying to get a value from result into sheet that matches by the Numer.
Your problem is that the whole query is being sent to SQL Server, and when it gets to the bit where you try to create an Admin object, SQL Server goes "Huh? What's one of those?"
If you enumerate your query before that point, then the results are sent back from SQL Server to your code, where the Admin object can be created...
var sheet = Context.Admins.AsNoTracking()
.ToList()
.Select(a => new Admin()
{
// some other variables
Numer = k.Numer,
AdminName = result.FirstOrDefault(a => a.Numer == k.Numer).AdminName ?? String.Empty
});
I've converted your code to use method syntax, as I think it's easier to read for this sort of thing.
Either way, the point is to understand what bit of code gets executed where. Anything to do with your models must be executed in your code, not in the database, as that doesn't know about your models. The call to ToList() enumerates the query (ie actually runs it against the database). Everything after that then happens in your code.
As a side point, you should really be using async code for this sort of thing...
var sheet = (await Context.Admins.AsNoTracking()
.ToListAsync())
//... other code as before
I have a class to handle some data :
public class User
{
public string Name;
public string Date;
}
In another class,i create a List of User class and add data as follows :
public class Display
{
List<User> userData = new List<User>;
private void add()
{
User udata = new User;
udate.Name = "Abc";
udata.Date = "1/1/18";
userData.Add(udata);
}
}
My question is, after adding some data,how do i update it ? Say i have added a data(udata is what i mean) with a Name of ABC,how do i update it?
Since your list contains a mutable type, all you need to do is get a reference to the specific item you want to update.
That can be done in a number of ways - using it's index, using the Find method, or using linq are the first three that comes to mind.
Using index:
userData[0]?.Name = "CBA";
Using Find:
userData.Find(u => u.Name = "Abc")?.Name = "CBA";
Using linq (FirstOrDefault is not the only option):
userData.FirstOrDefault(u => u.Name = "Abc")?.Name = "CBA";
Note the use of null conditional operator (]? and .?) it prevents a null reference exception in case the item is not found.
Update
As Ak77th7 commented (thanks for that!), the code in this answer wasn't tested and will cause a compilation error -
error CS0131: The left-hand side of an assignment must be a variable,
property or indexer
The reason for this is the null-conditional operator (?.).
You can use it to get values from properties, but not for setting them.
The fix is either to accept the fact that your code might throw a NullReferenceException (which I personally believe has no room in production-grade code) or to make your code a bit more cumbersome:
// Note: Possible null here!
userData.Find(u => u.Name.EndsWith("1")).Name = "Updated by Find";
// Safe, but cumbersome
var x = userData.FirstOrDefault(u => u.Name.EndsWith("2"));
if(x is not null)
{
x.Name = "Updated by FirstOrDefault";
}
See a live demo on SharpLab.IO
Nothing tricky, really (but does use System.Linq)
**EDIT: Changed Single to First to avoid error if there are two users with the same name. **
void Update(string name, string newName)
{
var user = userData.First(u => u.Name == name);
user.Name = newName;
}
Notice this changes the object, and the List maintains reference to the changed object.
I have a list List<OfferComparison> Comparison. I want to
check if all the items have Value == null in an if condition.
How can I do it with linq?
public class OfferComparison : BaseModel
{
public string Name { get; set; }
public string Value { get; set; }
public bool Valid { get; set; }
}
Updated (post C# 7) Answer
If using C# 7 or 8 then one could use the is keyword together with Linq.All:
var result = Comparison.All(item => item.Value is null)
If using C# 9 then one could use the is not null together with Linq.Any:
var result = Comparison.Any(item => item.Value is not null)
If using C# 9 then one could also use the is object or is {} together with Linq.Any:
var result = Comparison.Any(item => item.Value is object)
All these options are somewhat equivalent. At least in terms of time complexity they are all O(n). I guess the "preferred" option simply depends on personal opinion.
Original (pre C# 7) Answer
Using linq method of All:
var result = Comparison.All(item => item.Value == null)
Basically what it does is to iterate all items of a collection and check a predicate for each of them. If one does not match - result is false
You can check by this linq statement
var isNull = Comparison.All(item => item.Value == null);
I'm not totally sure about the internal differences of All and Exists, but it might be a good idea to just check whether one of the entries is not null and then negate the result:
var result = !Comparison.Exists(o => o.Value != null);
I would expect this query to quit after the first non-null value was found and therefore to be a little more efficient.
Update: From the Enumerable.All documentation:
The enumeration of source is stopped as soon as the result can be determined.
Therefore, using All will probably not result in the entire list getting processed after a non-null value has been found.
So the aforementioned possible performance gain is not likely to occur and both solutions probably do not differ.
How to allow null in Context.Request:
context.Response.Write(retrieveList(context.Request["SalCode"].ToString(null), context.Request["groupKeyword"].ToString(), context.Request["text"].ToString()));
Firstly, Request["..."] already returns a string, so there is no need to call ToString() on it and thus no need to worry, at this stage, if it returns null (i.e. if the key is not present in the request).
Thus you can call e.g.
retrieveList(
context.Request["SalCode"],
context.Request["groupKeyword"],
context.Request["text"]);
without worrying if any of the three are null.
You can then alter retrieveList to respond correctly if any of the inputs is null. For example, you could return null:
private string /*or whatever*/ retrieveList(
string salCode, string groupKeyword, string text)
{
if (String.IsNullOrEmpty(salCode) ||
String.IsNullOrEmpty(groupKeyword) ||
String.IsNullOrEmpty(text))
{
return null;
}
...
}
Then, note that Response.Write doesn't care if you give it a null, it just writes nothing, so you can keep the call to Write as above.
Alternatively, you could for example check the return value and write a message if it is null:
var list = retrieveList(
context.Request["SalCode"],
context.Request["groupKeyword"],
context.Request["text"]));
if (!String.IsNullOrEmpty(list))
{
context.Response.Write(list);
}
else
{
context.Response.Write("Missing request parameter.");
}
TYou didn't specify anything! Please add information, you even didn't specify the environment, the classes, or the general context in which this problem occurs. nor do we know what the signature of retrieveList() is! This makes us very difficult to help you! How much would you like to answer the question, one of my colleagues faced once: 'This crap doesn't work!' ? (Yes, it is not even a question, but happened in a real life support situatiuon!)
One thing I noted is that you use *T*oString() instead of *t*oString(), I assume that is a typo. (edited, as it is clear that this is C#) Also, I don't know what .toString(null) means. Did you want to tell us that that statement causes the NullPointerException? In that case, you could have committed a bit more effort towards us to understand your question, e.g. by writing this down...
BTW, if that's the case, I'd say, this will solve your problem:
Object salCode = context.Request["SalCode"];
context.Response.Write(retrieveList(salCode==null?"":salCode.ToString(), context.Request["groupKeyword"].ToString(), context.Request["text"].ToString()));
EDIT I think (but have no means to test) that if the null is the problem, this would fix it. If however, the underlying code does not work properly with empty String specified, that should be checked in retrieveList() like this (pasted from referenced post):
private string retrieveList(string SalCode, string groupKeyword, string text)
{
SqlConnection _sqlCon = default(SqlConnection);
SqlCommand _sqlCom = default(SqlCommand);
SqlDataReader _sqlReader = default(SqlDataReader);
StringBuilder _sb = new StringBuilder();
List<TokenInputJSON> _out = null;
try
{
_sqlCon = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["SalesianBlastConnectionString"].ConnectionString);
_sqlCom = new SqlCommand("getTokenInput", _sqlCon);
_sqlCom.CommandType = CommandType.StoredProcedure;
_sqlCon.Open();
//This is the edited part
if(SalCode==null || SalCode.Equals("")) {
_sqlCom.Parameters.Add(new SqlParameter("#salCode", SqlDbType.VarChar, 4)).Value = SalCode;
}
//... continue with the other parts
Quick check: I just had an idea: use a constant value when calling retrieveList to find out if this is the problem:
context.Response.Write(retrieveList("enterAValidSalCodeHere", context.Request["groupKeyword"].ToString(), context.Request["text"].ToString()));
I'm working with Simple.data, and the answer is not in the technology aforementioned but helps bring the point across. So ignore the syntax etc.
I am querying a database with a simple query; but based on a set of conditions, the query will change.
So for example: (very simplistic, probably 5-10 conditions)
var result;
if(LoggedAtSelected)
{
// Condition 1 - Calls Logged after a certain date
result = db.Jobs.FindAll(db.Jobs.Logged_At >= startDate);
}
else
{
// Condition 2 - Calls Closed after a certain date
result = db.Jobs.FindAll(db.Jobs.Closed_At >= startDate && dd.Jobs.Closed_At <= endDate);
}
foreach(var JobRecord in result)
{
}
This is the ideal code above, but sadly this is not possible given the dynamic binding and variable nature of var. What is the best practice for this kind of situation? My only idea is to write a "var result = condition..." for every condition, and in the if..else if..else, to assign it to a global variable after converting it to that type; and then using it in the "foreach". Sounds a lot of work. Any ideas? Or is that it!!!?!!!
Instead of:
var result;
Use the actual type returned by db.Jobs.FindAll:
IEnumerable<Job> result;
You can only use var if the compiler can know exactly which type to use (or how to define a new type for you).
In your case you can either define it with the type say
List<Job> result;
or call the constructor to return an instance:
var result = new List<Job>;
(of course your query will return an IEnumarable instance instead of a List, I just used List as an example because you can't instantiate an enumeration.)
Just as a note, as your if statements determine the filters for the query rather than the query itself, you might want to build up a SimpleExpression there and run the query afterwards. For example.
var whereCLause;
if(LoggedAtSelected)
{
// Condition 1 - Calls Logged after a certain date
whereClause = db.Jobs.Logged_At >= startDate;
}
else
{
// Condition 2 - Calls Closed after a certain date
whereClause = db.Jobs.Closed_At >= startDate && dd.Jobs.Closed_At <= endDate;
}
List<Job> results = db.Jobs.All.Where(whereClause);
foreach(Job record in results)
{
...
}