Linq replace null/empty value with another value - linq

In sql server I create views where I can check for null values and replace them with a default if I want (i.e. ISNULL(PrimaryPhone, 'No Primary #') AS PrimaryPhone. I used a lot of views in my asp.net web forms application, but I am now learning MVC 4 and want to start out right.
I have a model, controller and view set up for my client table. I would like to be able to replace null/empty values with ("Not Entered") or something like that.
I believe this needs to go in the controller, please correct me if I'm wrong.
I saw an example that uses hasvalue, but it is not available through intellisense.
How would I replace empty/null values without using DefaultValue in my model?
Thanks
var result = db.Clients.Select(x => new
{
CustomerID = x.CustomerID,
UserID = x.UserID,
FullName = x.FullName,
EmailAdd = x.emailadd.DefaultIfEmpty("No Email"),....

You can use the ?? operator to set a default value when something is null:
var result = db.Clients.Select(x => new
{
CustomerID = x.CustomerID,
UserID = x.UserID,
FullName = x.FullName,
EmailAdd = x.emailadd ?? "No Email", ...
If you need more control, for example checking for both null and empty, you can also use the ?: operator (also known as the "conditional operator" or "ternary operator"):
var result = db.Clients.Select(x => new
{
CustomerID = x.CustomerID,
UserID = x.UserID,
FullName = x.FullName,
EmailAdd = string.IsNullOrEmpty(x.emailadd) ? "No Email" : x.emailadd, ...

Related

mvc3 assign anonymous types or workaround

I have a model that is used to modify a user's password and captures the date that the password has been changed. I am getting an error saying property or indexer anonymous type cannot be assigned to it is read only I get that error for both fields the password and CreateDate . I only know of 1 way to select multiple fields from entity and this is it..
var old= db.registration.Where(b => b.email == getid.email).Select
(s => new { s.password, s.CreateDate }).FirstOrDefault();
old.CreateDate = DateTime.Now();
old.password = new.password;
db.Entry(old).State = EntityState.Modified;
db.SaveChanges();
Is there a way that I can assign these new values without getting the error message or a workaround ?
Just select the default object and run with it
var old= db.registration.Where(b => b.email == getid.email).FirstOrDefault();
old.CreateDate = DateTime.Now();
old.password = new.password;
db.Entry(old).State = EntityState.Modified;
db.SaveChanges();
The error message you're getting is likely because you're assigning to the index of an anonymous type, ie.
s => new { s.password, s.CreateDate }
is anonymous and its indexed properties cant be assigned to

LINQ performance when using nullable properties in select

I have an IEnumerable collection.
Using LINQ, I am populating the collection from a web service response.
Below is the sample I am using.
lookupData = from data in content["data"].Children()
select new LookupData
{
LookupKey = (data["data"]["key"]).ToString(),
LookupValue = (string)data["data"]["name"]
};
I will be using the same code for a lot of similar responses which will return a key and value.
Now, I got a scenario when I needed an additional field from the service response for few of the responses(not for all). So, I created an "Optional" property in "LookUpData" class and used as below:
lookupData = from data in content["data"].Children()
select new LookupData
{
LookupKey = (data["data"]["key"]).ToString(),
LookupValue = (string)data["data"]["name"],
Optional = referenceConfig.Optional != null
? (data["data"]["optional"]).ToString()
: String.Empty
};
The null check here is a performance issue. I do not want to use the below since I have other conditions and all together it will become a very big if else loop.
if(referenceConfig.Optional != null){
lookupData = from data in content["data"].Children()
select new LookupData
{
LookupKey = (data["data"]["key"]).ToString(),
LookupValue = (string)data["data"]["name"],
Optional = (data["data"]["optional"]).ToString()
};
}
else{
lookupData = from data in content["data"].Children()
select new LookupData
{
LookupKey = (data["data"]["key"]).ToString(),
LookupValue = (string)data["data"]["name"]
};
}
But I have at least 10 web server response with lots of data in each.
If the value of referenceConfig.Optional is available at compile time you can do
#if OPTIONAL
...
#else
...
If not - you can implement the Null Object Pattern i.e. have all of your ["data"][...] properties always return a value(for instance string.Empty if the type is string) so you won't have check explicitly in the code.

if-else clause in Linq to entity framework query

Following Linq to Entities query is causing the "Unable to create a constant value of type 'Data.InhouseUnit'. Only primitive types ('such as Int32, String, and Guid') are supported in this context" exception.
IList<FaultReport> faultReports = (from fr in _session.FaultReports
where fr.CreatedOn > dateTime
select new FaultReport
{
Id = fr.Id,
ExecutionDate = fr.ExecutionDate ?? DateTime.MinValue,
FaultType = fr.FaultType,
Quarters = fr.Quarters,
InhouseSpaceId = fr.InhouseSpaceId,
InhouseSpace = new InhouseSpace { Id = fr.InhouseSpace.Id, Name = fr.InhouseSpace.Name },
InhouseUnitId = fr.InhouseUnitId ?? Guid.Empty,
**InhouseUnit = fr.InhouseUnitId == Guid.Empty ? null : new InhouseUnit { Id = fr.InhouseUnit.Id, Name = fr.InhouseUnit.Name }**
}).ToList();
Specifically, it is the if expression in bold font which causes the exception. I need to make the check as fr.InhouseUnitId is a nullable. If I take out the the bolded expression, the rest of the statement works just fine. I have spent a fair amount of time, in msdn forum and on web, to understand what is causing the exception but still cannot quite understand. Guid is scalar so it should work, right? Even this expression InhouseUnit = true ? null: new InhouseUnit() in place of the bolded expression in the above statement wouldn't work. Can we even write if/else
If i try to write an extension method to take away the logic and just return a result, following exception is thrown:
LINQ to Entities does not recognize the method 'System.Object
GuidConversion(System.Nullable`1[System.Guid], System.Object)' method, and this method
cannot be translated into a store expression
It looks like you are projecting into new objects of the same type that you are querying from. Is that the case? It seems a little weird, but assuming you have a good reason for doing this, you could split the query into two parts. The first part would get what you need from the database. The second part would run locally (i.e. LINQ-to-Objects) to give you the projection you need. Something like this:
var query =
from fr in _session.FaultReports
where fr.CreatedOn > dateTime
select new {
fr.Id,
fr.ExecutionDate,
fr.FaultType,
fr.Quarters,
InhouseSpaceId = fr.InhouseSpace.Id,
InhouseSpaceName = fr.InhouseSpace.Name,
InhouseUnitId = fr.InhouseUnit.Id,
InhouseUnitName = fr.InhouseUnit.Name,
};
IList<FaultReport> faultReports = (
from fr in query.ToList()
select new FaultReport {
Id = fr.Id,
ExecutionDate = fr.ExecutionDate ?? DateTime.MinValue,
FaultType = fr.FaultType,
Quarters = fr.Quarters,
InhouseSpaceId = fr.InhouseSpaceId,
InhouseSpace = new InhouseSpace { Id = fr.InhouseSpaceId, Name = fr.InhouseSpaceName },
InhouseUnitId = fr.InhouseUnitId ?? Guid.Empty,
InhouseUnit = fr.InhouseUnitId == Guid.Empty ? null : new InhouseUnit { Id = fr.InhouseUnitId, Name = fr.InhouseUnitName }
}).ToList();

How to check for null attributes in LinqToXML expressions?

I have a LinqToXML expression where I am trying to select distinct names based on similar attributes. The code is working great and I've put it below:
var q = xmlDoc.Element("AscentCaptureSetup").Element("FieldTypes")
.Descendants("FieldType")
.Select(c => new { width = c.Attribute("Width").Value,
script = c.Attribute("ScriptName").Value,
sqlType = c.Attribute("SqlType").Value,
enableValues = c.Attribute("EnableValues").Value,
scale = c.Attribute("Scale").Value,
forceMatch = c.Attribute("ForceMatch").Value,
forceMatchCaseSensitive = c.Attribute("ForceMatchCaseSensitive").Value,
sortAlphabetically = c.Attribute("SortAlphabetically").Value,
})
.Distinct();
The problem arises since not all the attributes are required, and if one of them is omitted, for example sortAlphabetically, I get an Object not Referenced error. Makes sense, but it there a way to alter the query to only use assign the new values if the attribute actually exists? (Thereby bypassing any null pointer errors)
Instead of using the Value property (which will blow up on a null reference), simply cast the XAttribute to string - you'll either get the value, or a null reference if the XAttribute reference is null. (XElement works the same way, and this applies to all conversions to nullable types.)
So you'd have:
.Select(c => new {
width = (string) c.Attribute("Width"),
script = (string) c.Attribute("ScriptName"),
sqlType = (string) c.Attribute("SqlType"),
enableValues = (string) c.Attribute("EnableValues"),
scale = (string) c.Attribute("Scale"),
forceMatch = (string) c.Attribute("ForceMatch"),
forceMatchCaseSensitive = (string) c.Attribute("ForceMatchCaseSensitive"),
sortAlphabetically = (string) c.Attribute("SortAlphabetically"),
})
Some of those attributes sound like they should actually be cast to int? or bool?, mind you...

Only primitive types ('such as Int32, String, and Guid') are supported in this context when I try updating my viewmodel

I am having some trouble with a linq query I am trying to write.
I am trying to use the repository pattern without to much luck. Basically I have a list of transactions and a 2nd list which contains the description field that maps against a field in my case StoreItemID
public static IList<TransactionViewModel> All()
{
var result = (IList<TransactionViewModel>)HttpContext.Current.Session["Transactions"];
if (result == null)
{
var rewardTypes = BusinessItemRepository.GetItemTypes(StoreID);
HttpContext.Current.Session["Transactions"] =
result =
(from item in new MyEntities().TransactionEntries
select new TransactionViewModel()
{
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID).ItemDescription,
TransactionDate = item.PurchaseDate.Value,
TransactionAmount = item.TransactionAmount.Value,
}).ToList();
}
return result;
}
public static List<BusinessItemViewModel>GetItemTypes(int storeID)
{
var result = (List<BusinessItemViewModel>)HttpContext.Current.Session["ItemTypes"];
if (result == null)
{
HttpContext.Current.Session["ItemTypes"] = result =
(from items in new MyEntities().StoreItems
where items.IsDeleted == false && items.StoreID == storeID
select new BusinessItemViewModel()
{
ItemDescription = items.Description,
StoreID = items.StoreID,
StoreItemID = items.StoreItemID
}).ToList();
}
return result;
However I get this error
Unable to create a constant value of type 'MyMVC.ViewModels.BusinessItemViewModel'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
I know its this line of code as if I comment it out it works ok
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID).ItemDescription,
How can I map ItemDescription against my list of itemTypes?
Any help would be great :)
This line has a problem:
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID)
.ItemDescription,
Since you are using FirstOrDefault you will get null as default value for a reference type if there is no item that satifies the condition, then you'd get an exception when trying to access ItemDescription - either use First() if there always will be at least one match or check and define a default property value for ItemDescription to use if there is none:
ItemDescription = itemTypes.Any(r=>r.StoreItemID==item.StoreItemID)
? itemTypes.First(r=>r.StoreItemID==item.StoreItemID)
.ItemDescription
: "My Default",
If itemTypes is IEnumerable then it can't be used in your query (which is what the error message is telling you), because the query provider doesn't know what to do with it. So assuming the that itemTypes is based on a table in the same db as TransactionEntities, then you can use a join to achieve the same goal:
using (var entities = new MyEntities())
{
HttpContext.Current.Session["Transactions"] = result =
(from item in new entities.TransactionEntries
join itemType in entities.ItemTypes on item.StoreItemID equals itemType.StoreItemID
select new TransactionViewModel()
{
ItemDescription = itemType.ItemDescription,
TransactionDate = item.PurchaseDate.Value,
TransactionAmount = item.TransactionAmount.Value,
CustomerName = rewards.CardID//TODO: Get customer name
}).ToList();
}
I don't know the structure of your database, but hopefully you get the idea.
I had this error due a nullable integer in my LINQ query.
Adding a check within my query it solved my problem.
query with problem:
var x = entities.MyObjects.FirstOrDefault(s => s.Obj_Id.Equals(y.OBJ_ID));
query with problem solved:
var x = entities.MyObjects.FirstOrDefault(s => s.Obj_Id.HasValue && s.Obj_Id.Value.Equals(y.OBJ_ID));

Resources