LINQ Where(), what to do if I need to get everything? - linq

Consider the next example:
public List<Allergy> GetAllergies(int? ingredientId = null)
{
var allergies = new List<Allergy>();
var preSelect = ingredientId != null
? _dataContext.Ingredients.Where(x=> x.Id == ingredientId).SelectMany(x=>x.Allergies.AsQueryable())
: _dataContext.Allergies.AsQueryable();
preSelect.ToList().ForEach(x =>
{
var a = Mapper.Map<Database.Allergy, Allergy>(x);
allergies.Add(a);
});
return allergies;
}
That works, but I believe it's possible to get rid of null checking part and get all Ingredients if ingredientId is null right there in Where() body. How can we do that? Also any other suggestions to improve this piece of code will be appreciated.

Try this: You can think of the where clause as an if statement.
_dataContext.Ingredients.Where( x => x.Id != null && x.Id == ingredientId)
(Assuming x.Id is also of type int?)

Try this:
var preSelect =
_dataContext
.Ingredients
.Where
(
x=> (!ingredientId.HasValue || x.Id == ingredientId)
)
.SelectMany(x=>x.Allergies.AsQueryable());

Related

Null reference exception in linq select statement

I am getting a null reference exception from my bellow linq query. I have a table with an entityID(reference to another table to get translated text), but in some case i don't have proper translated text in my child table. This case i need to take lookupName field text and assign to lookupName field.
await _context.FormLookup.Where(x=>!(x.isDeleted))
.Select(x => new LookupList() {
lookupID = x.lookupID,
TransilatedName = _context.TranslatedText.FirstOrDefault(z => z.entityID == x.entityID && z.languageId == language && !(z.isDeleted)).languageText,
lookupName = x.lookupName,
itemCount = x.lookupDetails.Count(),
parent = x.parentID
}).ToListAsync();
I need to add a condition like
TransilatedName = _context.TranslatedText.FirstOrDefault(z => z.entityID == x.entityID && z.languageId == language && !(z.isDeleted)) != null ? TransilatedName = _context.TranslatedText.FirstOrDefault(z => z.entityID == x.entityID && z.languageId == language && !(z.isDeleted)).languageText : x.lookupName,
Any suggestions?
Select property LanguateText before you use FirstOrDefault:
var query = dbContext.FormLookup
.Where(x=>!(x.isDeleted))
.Select(x => new LookupList()
{
lookupID = x.lookupID,
TransilatedName = dbContext.TranslatedText
.Where(translatedText => translatedText.entityID == x.entityID
&& translatedText.languageId == language
&& !translatedText.isDeleted)
.Select(translatedText => translatedText.languageText)
.FirstOrDefault(),
...
});

Escape null values LINQ

I have an issue with this linq expression:
var invs = ids.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries)
.Select(x => sitecoreContext.GetItem<Inv>(new ID(x).Guid))
.ToList();
How can I check for null into the .Select? SitecoreContext.GetItem(new ID(x).Guid)) to crash (because items being unpublished, or created but not published) so I need a way to verify first if the item exist, and only then to make the select.
Thank you.
When you call SitecoreContext.GetItem<T>, in the background SitecoreContext gets the item from the database and then it casts it to the T type. And from what I can see, it can throw an exception if there is no item with the specified ID.
What you can do to avoid this exception is split what SitecoreContext does and execute it on your own with a null check in between:
Execute GetItem first
Do the null check
Cast the item to your type:
var invs = ids.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries)
.Select(x => sitecoreContext.Database.GetItem(new ID(x)))
.Where(x => x != null)
.Select(x => sitecoreContext.Cast<Inv>(x))
.ToList();
You can filter all non-null items using a where statement.
var nonNull = list.Where(element => element != null);
I usually use an extension method for this:
public static class EnumerableExtensions
{
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T> enumerable)
where T: class
{
return enumerable.Where(element => element != null);
}
}
Given your example, you could use the statement like this:
var invs = ids.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries)
.WhereNotNull()
.Select(x => sitecoreContext.GetItem<Inv>(new ID(x).Guid))
.ToList();
You Can Check Null Using null coalescing operator or ternary Operator in Linq Example is Given Below
`var productTypes = from ProductDto e in Product
select new
{
Id = e.Product != null ? e.Product.ID : 0,
Name = "xyz"
};`

Can't use == in LINQ Extension Method

I've got the following struct that is the key for my dictionary:
public struct CodeAttribute
{
public int ProcessorId;
public Enums.TransactionType transactionType;
public string ErrorMessage;
}
I've got the following dictionary (one value for now as it's just an example):
var errors = new Dictionary<CodeAttribute, int>
{
{CreateCodeAttributeList(2, Enums.TransactionType.Order, "Invalid ProcessorId sent in the Payment Request"), 100 }
};
And I'm trying to pull out the item in the dictionary that matches on the struct that has a match for both its ProcessorId and TransactionType properties:
private static string GetRelatedMessage(int errorCode, Dictionary<CodeAttribute, int> errorsList)
{
CodeAttribute codeAttribute = errorsList.Where(e => e.Key.ProcessorId == _processorId)
.Where(e => e.Key.transactionType == _transactionType) == errorCode;
return codeAttribute.ErrorMessage;
}
I also want to match on error code as part of the filtering, not just paymentprocessorId and transactionType, just a side note. The item in the dictionary must match all 3 values in order to get the right one in our case.
UPDATE
I tried this as well,and yes I get the error that it can't convert IEnumerable to CodeAtribute
CodeAttribute codeAttributes = errorsList.Where(e => e.Key.ProcessorId == _processorId)
.Where(e => e.Key.transactionType == _transactionType)
.Where(e => e.Value.Equals(errorCode));
UPDATE
with the help of Sam I think this may work
CodeAttribute codeAttribute = errorsList.FirstOrDefault(e => e.Key.ProcessorId ==
_processorId && e.Key.transactionType == _transactionType
&& e.Value == errorCode).Key;
If I understand correctly then you want
var codeAttribute = errorsList.FirstOrDefault(e =>
e.Key.ProcessorId == _processorId
&& e.Key.transactionType == _transactionType
&& e.Value == errorCode);
if(codeAttribute == null)
{
//no item matches in the dictionary.
}
return codeAttribute.Key.ErrorMessage;
Note that codeAttribute will be a KeyValuePair so you will need the codeAttribute.Key.ErrorMessage as your return value.
You don't need to use Where as that will return an IEnumerable so this won't work if you want a single item.
You probably need to go with something like this:
CodeAttribute codeAttribute = errorsList.FirstOrDefault(e => e.Key.ProcessorId == _processorId && e.Key.transactionType ==_transactionType)
While the other answers are correct, I would probably write it like this:
var errorMessage = errorsList
.Where(e => e.Key.ProcessorId == _processorId
&& e.Key.transactionType == _transactionType
&& e.Value == errorCode)
.Select(e => e.Key.ErrorMessage)
.FirstOrDefault();
That is, push the condition to filter earlier on, select the data I want from that result-set, and then take the first result (should one exist) of the transformed data.
Since the IEnumerable queries are lazy then this will still stop on the first sucessfully filtered object.
Since the source is a Dictionary, it may be also prudent to set up a relevant Equals/GetHashCode and structure the code such that it will be used.

Deep LINQ projections, how?

Let's say I have a model created with EF 4.0
User
Roles
Permissions
Each entity has a DeleteDate property.
I want to get a specific user (with Name =...) and have the tree filled with items where DeletedDate == null..
This must be done with anonymous type projection as result, but I don't know how to accomplish this with a hierachy deeper than 2..
This is what I already have:
public MyProjection MyCall(string givenName)
{
var result = from s in context.Users
where (s.Name == givenName &&
s.DeletedDate == null)
select new
{
s,
roles = from r in s.Roles
where r.DeletedDate == null
select r
};
var outcome = result.FirstOrDefault();
if (outcome != null)
{
var myProjection = new MyProjection()
{
User = outcome.s,
Roles = outcome.roles
};
return myProjection;
}
return null;
}
Depending on your structure you could do something like this:
var result = m.Users.Where(u => u.DeletedDate == null)
.Select( u => new
{
u,
roles = u.Roles.Where(r => r.DeletedDate == null)
.Select(r => new
{
r,
permissions = r.Permissions.Where(p => p.DeletedDate == null)
})
}).FirstOrDefault(item => item.u.Name == givenName);
If you retrieve with the following:
var result = from s in MyUsers
where s.DeletedDate == null
select new aUser{
Roles = (from r in s.Roles
where r.DeletedDate == null
select r).ToList()
};
And then create a TreeView:
TreeView treeView = new TreeView();
Then set the ItemsSource of the TreeView to the IEnumerable:
treeView.ItemsSource = result;
Then build a HierarchicalDataTemplate in your TreeView to represent your Lists (similar to this or for more in depth this), then voila!

How to check for nulls using LINQ

I have this code. How can I check for null values with the SingleOrDefault method?
public static List<ETY.Rol> GetRolesByApplicationAndCompany(this UsuarioContext usuario, int company, int app)
{
List<ETY.Company> lCompanies= usuario.Companies;
var roles = lCompanies.
SingleOrDefault(e => (e.Id == company)).Applications.
SingleOrDefault(a => a.Id == app).Roles;
return roles;
}
You could try looking at a Maybe/IfNotNull extension method (here and here).
Or use Linq syntax something like this (untested):
var q = from company in lCompanies.SingleOrDefault(e => e.Id == company)
where company != null
let application = company.Applications.SingleOrDefault(a => a.Id == app)
where application != null
select application.Roles;
(Greg Beech's answer is better if the Single condition is guaranteed)
Do you mean returning null or an empty list if any of the SingleOrDefault returns null? In that case:
var company = lCompanies.SingleOrDefault(e => (e.Id == company));
if(company != null) {
var application = company.Applications.SingleOrDefault(a => a.Id == app);
if(application!=null) {
return application.Roles;
}
}
return null; //Or: return new List<ETY.Rol>();
Rather than using SingleOrDefault you could write a chained query as follows. You lose the semantics of ensuring that there's only a single application or company, but if you know that to always be the case then it shouldn't be a problem.
return from c in lCompanies where c.Id == company
from a in c.Applications where a.Id == app
select a.Roles;

Resources