Linq to entities OrderBy() - c#

I have a list with addresses and each address has a 'From' property. I want to order them on that property using Linq.
This is what I have:
var orderedAddresses = addresses.OrderBy(?what goes here?);

This should be the code you are looking for assuming that your field is From
var orderedAddresses = addresses.OrderBy(x => x.From);
To OrderBy two columns you can use
var orderedAddresses = addresses.OrderBy(x => x.From).ThenBy(y => y.AnotherField);

Related

dynamic property name in linq

I'm trying to write a linq query that takes a dynamic property name. So for example, if the property name is 'test', a simple query would look like this:
var test = testList.Select(x => x.test).Distinct().ToList();
But I want to dynamically generate the property name, eg:
var propertyName = "test";
var test = testList.Select(x => x.propertyName).Distinct().ToList();
I get an error because 'propertyName' isn't an actual property.
What would be the best way to achieve this?
You'd have to use reflection to do what you're trying to do:
var test = testList
.Select(x => x.GetType().GetProperty(propertyName).GetValue(x))
.Distinct()
.ToList();

Select distinct column names in Linq

My table contains several columns and I need to select distinct rows in two specific columns using Linq.
My SQL equivalent is:
Select distinct Level1Id, Level1Name
from levels
What I currently do is:
db.levels.GroupBy(c=> c.Level1Id).Select(s => s.First())
This will retrieve the whole row not only Level1Id and Level1Name. How can I specify the columns I want to retrieve in this linq query?
With Select, you can specify the columns in an anonymous object and then use Distinct on that:
db.levels.Select(l => new{ l.Level1Id, l.Level1Name }).Distinct();
try
db.levels.Select(c => new {c.Level1Id, c.Level1Name}).Distinct();
Specify the two columns in your LINQ query select, create an anonymous object with Level1Id and Level1Name properties:
var query = (from v in db.levels
select new { Level1Id = v.Level1Id, Level1Name = v.Level1Name }).Distinct();
and use each item like this:
foreach (var r in query){
int valId = r.LevelId;
int level = r.Level1Name;
//do something
}
You are so close, one more step:
var result = db.levels.GroupBy(c=> new { c.Level1Id, c.Level1Name })
.Select(s => s.First())
The key thing is: Anonymous type uses structural comparison, that's why GroupBy or any other answer do work.

Multiple Include and Where Clauses Linq

I have a database where I'm wanting to return a list of Clients.
These clients have a list of FamilyNames.
I started with this
var query = DbContext.Clients.Include(c => c.FamilyNames).ToList() //returns all clients, including their FamilyNames...Great.
But I want somebody to be able to search for a FamilyName, ifany results are returned, then show the clients to the user.
so I did this...
var query = DbContext.Clients.Include(c => c.FamilyNames.Where(fn => fn.familyName == textEnteredByUser)).ToList();
I tried...
var query = DbContext.Clients.Include(c => c.FamilyNames.Any(fn => fn.familyName == textEnteredByUser)).ToList();
and...
var query = DbContext.FamilyNames.Include(c => c.Clients).where(fn => fn.familyname == textEnteredByUser.Select(c => c.Clients)).ToList();
What I would like to know (obviously!) is how I could get this to work, but I would like it if at all possible to be done in one query to the database. Even if somebody can point me in the correct direction.
Kind regards
In Linq to Entities you can navigate on properties and they will be transformed to join statements.
This will return a list of clients.
var query = DbContext.Clients.Where(c => c.FamilyNames.Any(fn => fn == textEnteredByUser)).ToList();
If you want to include all their family names with eager loading, this should work:
var query = DbContext.Clients.Where(c => c.FamilyNames.Any(fn => fn == textEnteredByUser)).Include(c => c.FamilyNames).ToList();
Here is some reference about loading related entities if something doesn't work as expected.
You can use 'Projection', basically you select just the fields you want from any level into a new object, possibly anonymous.
var query = DbContext.Clients
.Where(c => c.FamilyNames.Any(fn => fn == textEnteredByUser))
// only calls that can be converted to SQL safely here
.Select(c => new {
ClientName = c.Name,
FamilyNames = c.FamilyNames
})
// force the query to be materialized so we can safely do other transforms
.ToList()
// convert the anon class to what we need
.Select(anon => new ClientViewModel() {
ClientName = anon.ClientName,
// convert IEnumerable<string> to List<string>
FamilyNames = anon.FamilyNames.ToList()
});
That creates an anonymous class with just those two properties, then forces the query to run, then performs a 2nd projection into a ViewModel class.
Usually I would be selecting into a ViewModel for passing to the UI, limiting it to just the bare minimum number of fields that the UI needs. Your needs may vary.

How to make lambda do one db call instead of severals

Is this example bad practice because it make several database calls?
Is it any way I can make this to one DB call? Like use 'where' instead of 'firstOrDefault' and compare FlagDate with each date on the message in my messageList?
foreach (var message in messageList)
{
var dayFlag = db.DayFlags.FirstOrDefault(x =>
x.FlagDate == message.MessageDate);
}
If you want to retrieve only the dayFlags which a corresponding Date to the messageList, you need to extract the dates first in a separate list, then pass it to a Linq To Sql query.
Note that to retrieve only the first DayFlags of each Date, you need to group the flags by date.
var dates = messageList.Select(m => m.MessageDate).ToList();
var dayFlags = db.DayFlags.GroupBy(flag => flag.FlagDate)
.Where(group => dates.Contains(group.Key))
.Select(group => group.First());
This is a solution with linq:
var dates = messageList.Select(m => m.MessageDate).ToList();
var dayFlags = from df in db.DayFlags
where dates.Contains(df.FlagDate)
select df;

Order query by int from an ordered list LINQ C#

So I am trying to order a query by an int var that is in an ordered list of the same int vars; e.g. the query must be sorted by the lists order of items. Each datacontext is from a different database which is the reason i'm making the first query into an ordered list of id's based on pet name order, only the pet id is available from the second query's data fields, Query looks like:
using (ListDataContext syndb = new ListDataContext())
{
using (QueryDataContext ledb = new QueryDataContext())
{
// Set the order of pets by name and make a list of the pet id's
var stp = syndb.StoredPets.OrderBy(x => x.Name).Select(x => x.PetID).ToList();
// Reorder the SoldPets query using the ordered list of pet id's
var slp = ledb.SoldPets.OrderBy(x => stp.IndexOf(x.petId)).Select(x => x);
// do something with the query
}
}
The second query is giving me a "Method 'Int32 IndexOf(Int32)' has no supported translation to SQL." error, is there a way to do what I need?
LINQ to SQL (EF) has to translate your LINQ queries into SQL that can be executed against a SQL server. What the error is trying to say, is that the .NET method of IndexOf doesn't have a SQL equivalent. You may be best to get your data from your SoldPets table without doing the IndexOf part and then doing any remaining ordering away from LINQ to SQL (EF).
Something like this should work:
List<StoredPet> storedPets;
List<SoldPet> soldPets;
using (ListDataContext listDataContext = new ListDataContext())
{
using (QueryDataContext queryDataContext= new QueryDataContext())
{
storedPets =
listDataContext.StoredPets
.OrderBy(sp => sp.Name)
.Select(sp => sp.PetId)
.ToList();
soldPets =
queryDataContext.SoldPets
.ToList();
}
}
List<SoldPets> orderedSoldPets =
soldPets.OrderBy(sp => storedPets.IndexOf(sp.PetId))
Note: Your capitalisation of PetId changes in your example, so you may wish to look at that.
LinqToSql can't transalte your linq statement into SQL because there is no equivalent of IndexOf() method. You will have to execute the linq statement first with ToList() method and then do sorting in memory.
using (ListDataContext syndb = new ListDataContext())
using (QueryDataContext ledb = new QueryDataContext())
{
var stp = syndb.StoredPets.OrderBy(x => x.Name).Select(x => x.PetID).ToList();
// Reorder the SoldPets query using the ordered list of pet id's
var slp = ledb.SoldPets.ToList().OrderBy(x => stp.IndexOf(x.petId));
}
You can use this, if the list size is acceptable:
using (ListDataContext syndb = new ListDataContext())
{
using (QueryDataContext ledb = new QueryDataContext())
{
var stp = syndb.StoredPets.OrderBy(x => x.Name).Select(x => x.PetID).ToList();
var slp = ledb.SoldPets.ToList().OrderBy(x => stp.IndexOf(x.petId));
// do something with the query
}
}

Categories