Escape null values LINQ - 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"
};`

Related

Reflection within IQueryable in .NET Core

I am wondering how would the below code work and what would be the performance. I am interested in line #4 basically. How will linq and property info work together?
In other words will (int)prop.GetValue(a) and a.SomeId work the same way or will the reflection need to get everything to memory before checking the value?
var prop = type.GetProperty("SomeId");
if (prop != null)
{
DbSet<T> dbSet = _dbContext.Set<T>();
return dbSet.Where(a => (int)prop.GetValue(a) == 1);
}
In other words will (int)prop.GetValue(a) and a.SomeId work the same way
No.
Depending on the backing store, the context may fail to convert that expression ((int)prop.GetValue(a)) to the underlying query syntax, which in most cases would be SQL.
You could consider building a valid expression manually using the property info.
For example
//Assuming
Type type = typeof(T);
PropertyInfo prop = type.GetProperty("SomeId");
if (prop != null) {
//need to build a => a.SomeId == 1
// a =>
ParameterExpression parameter = Expression.Parameter(type, "a");
// a => a.SomeId
MemberExpression property = Expression.Property(parameter, prop);
// a => a.SomeId == 1
BinaryExpression body = Expression.Equal(property, Expression.Constant(1));
Expression<Func<T, bool>> expression = Expression.Lambda<Func<T, bool>>(body, parameter);
DbSet<T> dbSet = _dbContext.Set<T>();
return dbSet.Where(expression);
}

LINQ select null values from List

I have a List<string> and it may contain null values in random indexes. I want to check which elements null and select that elements for throwing message.
What i am using;
List<string> getNames = EbaUsers.GetNamesFromIds(activeDirectoryInfo[7],
activeDirectoryInfo[8], activeDirectoryInfo[9], activeDirectoryInfo[10]);
if(getNames[7].Equals(null))
{
MessageBox.Show("getNames[7] is null");
}
if(getNames [8].Equals(null))
{
MessageBox.Show("getNames[8] is null");
}
if(getNames[9].Equals(null))
{
MessageBox.Show("getNames[9] is null");
}
if(getNames[10].Equals(null))
{
MessageBox.Show("getNames[10] is null");
}
I know this is very easy to do with LINQ but i haven't found anywhere.
Thanks for your help.
Sounds like you want to first project the strings to index/value pairs, then pick the elements with null values, and project to just the indexes:
var nullIndexes = names.Select((value, index) => new { value, index })
.Where(pair => pair.value == null)
.Select(pair => pair.index)
.ToList();
You need to get the index by Enumerable.Select() with index and check if the info is null:
var nullInfoIndexes = activeDirectoryInfo.Select((info, index) => new {info, index})
.Where(x => x.info == null)
.Select(x => x.index);
foreach (var index in nullInfoIndexes)
MessageBox.Show("activeDirectoryInfo[" + index + "] is null");

How to Search through all fields in a LINQ table?

in LINQ how do i search all fields in a table, what do i put for ANYFIELD in the below?
Thanks
var tblequipments = from d in db.tblEquipments.Include(t => t.User).Include(t => t.ChangeLog).Include(t => t.AssetType)
where d."ANYFIELD" == "VALUE" select d;
You can't. You must compare each field individually. It doesn't make sense to compare all fields, given a field may not even be of the same type as the object you're comparing to.
You can, using reflection. Try this:
static bool CheckAllFields<TInput, TValue>(TInput input, TValue value, bool alsoCheckProperties)
{
Type t = typeof(TInput);
foreach (FieldInfo info in t.GetFields().Where(x => x.FieldType == typeof(TValue)))
{
if (!info.GetValue(input).Equals(value))
{
return false;
}
}
if (alsoCheckProperties)
{
foreach (PropertyInfo info in t.GetProperties().Where(x => x.PropertyType == typeof(TValue)))
{
if (!info.GetValue(input, null).Equals(value))
{
return false;
}
}
}
return true;
}
And your LINQ query:
var tblequipments = from d in db.tblEquipments.Include(t => t.User).Include(t => t.ChangeLog).Include(t => t.AssetType)
where CheckAllFields(d, "VALUE", true) select d;
The third parameter should be true if you want to check all fields and all properties, and false if you want to check only all fields.
EDIT: Someone already built this...see here.
Not a full answer, but I don't agree with assertion that you simply can't...
You could come up with an extension method that dynamically filtered the IQueryable/IEnumerable (I'm guessing IQueryable by the db variable) based on properties of a similar type for you. Here's something whipped up in Linqpad. It references PredicateBuilder and is by no means complete/fully accurate, but I tested it out in Linq-to-SQL on some of my tables and it worked as described.
void Main()
{
YourDbSet.WhereAllPropertiesOfSimilarTypeAreEqual("A String")
.Count()
.Dump();
}
public static class EntityHelperMethods
{
public static IQueryable<TEntity> WhereAllPropertiesOfSimilarTypeAreEqual<TEntity, TProperty>(this IQueryable<TEntity> query, TProperty value)
{
var param = Expression.Parameter(typeof(TEntity));
var predicate = PredicateBuilder.True<TEntity>();
foreach (var fieldName in GetEntityFieldsToCompareTo<TEntity, TProperty>())
{
var predicateToAdd = Expression.Lambda<Func<TEntity, bool>>(
Expression.Equal(
Expression.PropertyOrField(param, fieldName),
Expression.Constant(value)), param);
predicate = predicate.And(predicateToAdd);
}
return query.Where(predicate);
}
// TODO: You'll need to find out what fields are actually ones you would want to compare on.
// This might involve stripping out properties marked with [NotMapped] attributes, for
// for example.
private static IEnumerable<string> GetEntityFieldsToCompareTo<TEntity, TProperty>()
{
Type entityType = typeof(TEntity);
Type propertyType = typeof(TProperty);
var fields = entityType.GetFields()
.Where (f => f.FieldType == propertyType)
.Select (f => f.Name);
var properties = entityType.GetProperties()
.Where (p => p.PropertyType == propertyType)
.Select (p => p.Name);
return fields.Concat(properties);
}
}
Useful resources for the unresolved part:
Finding the relevant properties
if this help some one.
first find all properties within Customer class with same type as query:
var stringProperties = typeof(Customer).GetProperties().Where(prop =>
prop.PropertyType == query.GetType());
then find all customers from context that has at least one property with value equal to query:
context.Customer.Where(customer =>
stringProperties.Any(prop =>
prop.GetValue(customer, null) == query));

Set the list value using linq

Hi I want to set the value in the list of objects that matches the given condition in the where clause.Is it possible?
Other work around is to get the list of objects using where clause and then iterate using for Or foreach loop and update the value.
listOfRequestAssigned.Where(x => x.RequestedNumber == CurrentRequest);
I have list listOfRequestAssigned of objects and want to update some propery of the objects that match my search criteria.
class Request
{
bool _requestCompleted;
int _requestedNumber;
public int RequestedNumber
{
get { return _requestedNumber; }
set { _requestedNumber = value; }
}
public bool RequestCompleted
{
get { return _requestCompleted; }
set { _requestCompleted = value; }
}
}
I want to update RequestCompleted property of all objects that match criteria using Linq
You can use ForEach in Linq
listOfRequestAssigned.Where(x => x.RequestedNumber == CurrentRequest).ToList().ForEach(x => x.RequestCompleted = true);
if you have more than one update to do,
listOfRequestAssigned.Where(x => x.RequestedNumber == CurrentRequest).ToList().ForEach(x => { x.RequestCompleted = true; x.OtherProperty = value; } );
Where(...) give you a query, not a Request or a List<Request>. Use FirstOrDefault() if you want to have one (or 0) result, or ToList() if you want to have a list of results on wich you can use ForEach().
In general Linq is a query- not an update tool, but you can use a foreach:
var currentRequests = listOfRequestAssigned
.Where(x => x.RequestedNumber == CurrentRequest);
foreach(var req in currentRequests)
{
req.RequestCompleted = true;
}
Since you have specific collection of type List, you can just use ForEach and a conditional set:
listOfRequestAssigned.Foreach(x => { if (x.RequestedNumber == CurrentRequest) x.RequestCompleted = true;}});
If you had a more generic collection IEnumerable, you can use Select in Linq to build a projection where property will be set as desired (original collection will be left untouched!):
listOfRequestAssigned
.Where(x => x.RequestedNumber == CurrentRequest)
.Select(x => { x.RequestCompleted = true; return x; })
You can use to assign boolean value by following on comparing time. This is the very simplest and smart way for bool property.
listOfRequestAssigned.ForEach(x => x.RequestCompleted = x.RequestedNumber
== CurrentRequest);

how to query the settingspropertyvaluecollection

I have a settingspropertyvaluecollection.I dont want to loop through all the properties using a for each loop.Instead i want to query the collection.How do i do that?is there a way to use LINQ and do it?
Thanks
SettingsPropertyValueCollection doesn't implement IEnumerable<T> but it does implement IEnumerable. If you want to query it using LINQ you have a couple of options.
You could create a Where() extension method that takes IEnumerable and a query and performs the query for you:
public static class IEnumerableExtensions
{
public static IEnumerable<T> Where<T>(this IEnumerable input, Func<T,bool> query)
{
return input.Cast<T>().Where(item => query(item));
}
}
assuming:
var settings = new SettingsPropertyValueCollection
{
new SettingsPropertyValue(new SettingsProperty("Email")
{
DefaultValue = "a#a.com",
PropertyType = typeof(string)
}),
new SettingsPropertyValue(new SettingsProperty("City")
{
DefaultValue = "Austin",
PropertyType = typeof(string)
}),
new SettingsPropertyValue(new SettingsProperty("State")
{
DefaultValue = "TX",
PropertyType = typeof(string)
})
};
usage would be:
var matches = settings.Where<SettingsPropertyValue>(x => x.Name == "City")
alternatively you could use the LINQ Cast<T> operator to query the settings:
var matches = settings.Cast<SettingsPropertyValue>()
.Where(x => x.Name == "City");
if you expect only one possible match then use FirstOrDefault() instead of Where()
var match = settings.Cast<SettingsPropertyValue>()
.FirstOrDefault(x => x.Name == "City");
It's been a while since the question was answered and many things have changed since then.
You could cast the SettingsPropertyValueCollection to a list (or other container) and query it right away.
So, this would be my solution nowadays:
SettingsPropertyValueCollection settings = Properties.Settings.Default.PropertyValues
settings.Cast<SettingsPropertyValue>().ToList().Where(p => p.Name == "myProperty");

Resources