Linq - Conditional Where / Find - c#

I have the following 2 lines,
var productStrucutre = _service.GetProductStructureWithParent(partId).ToList(); // returns a list of objects
var product = productStrucutre.Find(_ => _.Part == part); // Returns a part
if the following condition fails because the part does not exist, then i would like to return the whole product structure.
var product = productStrucutre.Find(_ => _.Part == part);
So the find will fall away

I assume you mean something like this:
var productStructure = _service.GetProductStructureWithParent(partId).ToList();
var product = productStrucutre.Where(x => x.Part == part);
return product.Any() ?
product : // return only those products that fit the condition
productStructure; // return all objects

Related

Linq code doesn't return correct record

I have a table named dbo.EmployeeType with three records:
PK_EmployeetypeID EmployeeTypeName
1 Project Manager
2 Business Analyst
3 Developer
I have this piece of Linq code:
public static string GetTypeByID(int id)
{
using (ProjectTrackingEntities1 db = new ProjectTrackingEntities1())
{
var type = db.EmployeeTypes.Select(o => new LOOKUPEmployeeType
{
PK_EmployeeTypeID = id,
EmployeeTypeName = o.EmployeeTypeName
});
return type.FirstOrDefault().EmployeeTypeName;
}
}
No matter what id I send to it, it returns Project Manager, and I'm confused as to why.
You need to apply a filter, otherwise you're just returning the first record and hard coding the ID. Try this:
public static string GetTypeByID(int id)
{
using (ProjectTrackingEntities1 db = new ProjectTrackingEntities1())
{
//Here we apply a filter, the lambda here is what creates the WHERE clause
var type = db.EmployeeTypes
.FirstOrDefault(et => et.PK_EmployeeTypeID == id);
if(type != null)
{
return type.EmployeeTypeName;
}
else
{
return "";
}
}
}
Note that using FirstOrDefault means if there are no matches, or multiple matches, type will be null and you will get an empty string returned.
Set a breakpoint on type = ... and inspect it. You have no Where in there so you get all - and Select just makes LOOKUPEmployeeTypes out of all of them.
FirstOrDefault then returns the first of those 3 which is always the ProjManager
Fix:
var type = db
.EmployeeTypes
.Where( o => o.Id == id)
.Select(o => new LOOKUPEmployeeType
{
PK_EmployeeTypeID = id,
EmployeeTypeName = o.EmployeeTypeName
});
In your code you only return the first value. You need to tell EF which value you need to return.
Let us assume you need the value with Id=2. Instead of Select(), use Single(x => x.Id == 2) or First(x => x.Id == 2).

Linq to find inside Array of objects

I have the below code . Here i want to find out servicelevelid in lstServiceLevels List which is an array of objects of ServiceLevelDetails where ServiceLevelName is "Basic"
Could anyone please help me to get it ?
public class ServiceLevelDetails
{
public int servicelevelid;
public string ServiceLevelName;
}
class Program
{
static void Main(string[] args)
{
IList<ServiceLevelDetails> lstServiceLevels = new List<ServiceLevelDetails>();
ServiceLevelDetails one = new ServiceLevelDetails();
one.servicelevelid=1;
one.ServiceLevelName="Basic";
ServiceLevelDetails Two = new ServiceLevelDetails();
Two.servicelevelid = 2;
Two.ServiceLevelName = "Enhanced";
lstServiceLevels.Add(one);
lstServiceLevels.Add(Two);
var test = from LevelName in lstServiceLevels
let LevelName= obj as ServiceLevelDetails
where LevelName.ServiceLevelName == "Basic"
select LevelName;
//getting error in the above code .
}
}
There is nothing in your scope called obj, so it's not clear why this is in your query.
In LINQ query syntax, it sounds like you want this:
from serviceLevel in lstServiceLevels
where serviceLevel.ServiceLevelName == "Basic"
select serviceLevel;
Or in LINQ method syntax:
lstServiceLevels.Where(x => x.ServiceLevelName == "Basic");
If, as you suggest in the comments, you want the id for a specific name:
var id = lstServiceLevels
.Where(x => x.ServiceLevelName == "Basic")
.Select(x => x.servicelevelid)
.Single();
here is an alternative with which you don't run into exceptions
when the element cannot be found.
look for the first occurrence of this element:
// FirstOrDefault will return null if nothing was found
// but it also will return only the first element!
var id_test = lstServiceLevels.FirstOrDefault(x => x.ServiceLevelName == "Basic");
// then you can check for it and take the ID if it was found
// or else assign some other value
int id = id_test != null ? id_test.servicelevelid : 0;
it's of course a matter of taste either to use try/catch or null testing :)

Distinct() linq query

I am trying to filter my linq query, using distinct() method but I keep getting all the data records (including duplication). I have tried the following variations, which all seem to be failing.
int total = Data.Count();
// Data = Data.GroupBy(member => member.Tag).Select(x => x.OrderBy(y => y.Name).First());
// Data = Data.OrderByDescending(c => c.UploadDate);
Data = Data.Distinct().OrderBy(value => value.Tag);
var data = Data.ToList();
How can I filter my query by showing all the data fieldnames which are filtered by unique tags field name? My tag fieldname does contain NULL data as well.
Here is my entire method, for further reference:
[Authorize]
[HttpPost]
private HttpResponseMessage method(HttpContext request, Query query)
{
if (User.IsInRole("admin") || User.IsInRole("art"))
{
IQueryable<database_B> Data = null;
if (!string.IsNullOrEmpty(query.name))
{
var ids = query.name.Split(',');
// var dataMatchingTags = db.database_B.Where(c => ids.Any(id => c.Name.Contains(id)));
if (Data == null)
Data = dataMatchingTags;
else
Data = Data.Union(dataMatchingTags);
}
if (Data == null) // If no tags or name is being queried, apply filters to the whole set of products
Data = db.database_B;
if (query.endDate != null)
{
Data = Data.Where(c => c.UploadDate <= query.endDate);
}
if (query.startDate != null)
{
Data = Data.Where(c => c.UploadDate >= query.startDate);
}
int total = Data.Count();
// Data = Data.GroupBy(member => member.Tag).Select(x => x.OrderBy(y => y.Name).First());
// Data = Data.OrderByDescending(c => c.UploadDate);
Data = Data.Distinct().OrderBy(value => value.Tag);
var data = Data.ToList();
if (!data.Any())
{
var message = string.Format("No data found");
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
// return Request.CreateResponse(HttpStatusCode.OK, data);
return Request.CreateResponse(HttpStatusCode.OK, new { total, data });
}
Thank you for any further help.
You need something like that ?
http://www.codeproject.com/Articles/535374/DistinctBy-in-Linq-Find-Distinct-object-by-Propert
If database_B is a class (as opposed to a struct) which does not implement IEquatable<database_B> in a suitable way, Distinct will treat different objects as different, regardless of member values. A possible solution would be to implementet IEquatable<database_B> to reflect the comparision which is desired for equality.
Alternatively, a different overload of Distinct can be used, where it is possible to give a custom comparision as an argument.
Your class database_B has to implement Equals- and GetHashCode-Method in order to tell the Distinct under which circumstances two instances are considered equal and may therefor be filtered out.

Optimize query using HQL / Antlr.Runtime.NoViableAltException

I have code:
if (request.OrderBy != "PricesCount")
query = query.ApplyOrder(request);
else
{
if (request.OrderDirection == "ASC")
{
query = query.ToList().OrderBy(p => p.Prices.Count).AsQueryable(); //must be optimize!
}
else
query = query.ToList().OrderByDescending(p => p.Prices.Count).AsQueryable(); //must be optimize!
}
query = query.Page(pageNumber, pageSize);
var result = query.ToList();
query has type NHibernate.Linq.NhQueryable<Book>
I must remove the ToList() which causes loading all Books from DB.
If I try to use some code:
query = query.OrderBy(p => p.Prices.Count);
...
var result = query.ToList();//I have Antlr.Runtime.NoViableAltException
Exception of type 'Antlr.Runtime.NoViableAltException' was thrown. [.Take[Book](.Skip[Book](.OrderBy[Book,System.Int32](NHibernate.Linq.NhQueryable`1[Book], Quote((p, ) => (p.Prices.Count)), ), p1, ), p2, )]
result = query.Where(p=>p.Price > 5).ToList(); //put whatever filter you want
You don't need to do .ToList().AsQueryable().ToList() like you are in your first segment.
If you can't filter results, then you should implement some sort of paging:
result = query.Skip(x).Take(y).ToList(); //You will need to send in X and Y based on what page you are on and how many items per page you use
result = query.Where(p=>p.Price>5).OrderBy(p=>p.Prices.Count).ToList()
Like I said in comments, if you don't provide a where clause, or if you don't do .Take(y) then this will return all items in the database. You will pass in X and Y yourself if you do .Skip(x).Take(y), you need to determine what is appropriate paging for your application.

Using nested Any() method

Suppose you wanna test or compare the equality of two Vectors.
Suppose you have:
string[] models = {"ModelOne", "ModelTwo", "ModeThree"};
And another one that you don't know for sure what will be inside of it, but you believe that it will contain the same elements like models owner above.
I have this method to make this verification and I use it in a Unit test passing the vector models presented above.
public bool TemplateForDependenciesTests (string[] v)
{
var dependency = new Dependencies();
var result = dependency.GetByReferencedModel(typeof(T).ToString());
//foreach (var i in result)
//{
//if ((v.Any(model => model == i.ReferencingModelName)))
//return false;
//}
return result.Any(x => (v.Any(model => model == x.ReferencingModelName)));
}
the result variable will hold the return of this method:
public IEnumerable<Dependency> GetByReferencedModel(string referencedModelName)
{
return this.dependencies
.Where(d => d.ReferencedModelName == referencedModelName);
}
The question is: How can I make that return statement in TemplateForDependenciesTests() work nicely and in a way I can snoop that indeed it is doing what I expect, because till now I moved some stones here and there, but it appears not doing what I want?
It looks like you're just trying to see if any member of result has a ReferencingModelName that's in the models collection. Seems like this would do it:
return result.Select(x => x.ReferencingModelName).Intersect(v).Any();
Now, if you want to snoop to see if it's really doing what you expect:
var intersection = result.Select(x => x.ReferencingModelName).Intersect(v).ToList();
// now you can examine the contents of the intersection list
// and you can return the result
return intersection.Any();
You might even go one step further:
var result = dependency.GetByReferencedModel(typeof(T).ToString()).ToList();
var names = result.Select(x => x.ReferencingModelName).ToList();
var intersection = names.Intersect(v).ToList();
return intersection.Any();
With that, you can examine the results of each step, and you should be able to see where the error exists.
Order doesn't matter to Intersect. That is if you have:
var x = new string["a", "b", "c"];
var y = new string["c", "b"];
var z = new string["b", "c"];
Then x.Intersect(y) == y.Intersect(x) == x.Intersect(z) == y.Intersect(z), etc.
You could make your lambdas easier to debug by making them multi-line statements. E.g. you could put breakpoints all over this to see exactly what's happening.
var resultList = result.ToList();
return resultList.Any(x =>
{
bool outer = v.Any(model =>
{
bool inner = model == x.ReferencingModelName;
return inner;
});
return outer;
});
I'll also note that with things like ToLookup or ToDictionary, and HashSet<T>, you could make all of these lookups much faster and more intuitively-coded.

Categories

Resources