preserving the order of returning entities when using .Contains(Id) - linq

I want to hydrate a collection of entities by passing in a List of Ids and also preserve the order.
Another SO answer https://stackoverflow.com/a/15187081/1059911 suggested this approach to hydrating the entities which works great
var entities = db.MyEntities.Where(e => myListOfIds.Contains(e.ID)).ToList();
however the order of entities in the collection is different from the order of Ids
Is there a way to preserve the order?

May be that helps:
var entities = db.MyEntities
.Where(e => myListOfIds.Contains(e.ID))
.OrderBy(e => myListOfIds.IndexOf(e.ID)).ToList();
EDIT
JohnnyHK clarified that this will not work with LINQ to Entities. For this to work you need to order IEnumerable instead of IQueryable, since IQueryProvider don't know how to deal with local list IndexOf method when it sends query to server. But after AsEnumerable() OrderBy method deals with local data. So you can do this:
var entities = db.MyEntities
.Where(e => myListOfIds.Contains(e.ID))
.AsEnumerable()
.OrderBy(e => myListOfIds.IndexOf(e.ID)).ToList();

Entity Framework contains a subset of all of the LINQ commands so you won't have all the commands that LINQ to Objects has.
The following approach should give you your list of MyEntities in the same order as supplied by myListOfIds:
var entities = myListOfIds.Join(db.MyEntities, m => m, e => e.ID, (m,e) => e)
.ToList();

Related

Get All Entities From EntityCollection Where Values Matches X

I would like to get all matched Entities from an EntityCollection by a value, but my current statement only allow return of Entity, and not EntityCollection.
//only allow return 1 entity
var matchedRecords = allRecords.Entities.Where
(x => x.GetAttributeValue<EntityReference>
("ccc_batchId").Id == batchId);
May I know how can I tweak the above query?
EntityCollection is just a construct to store more than one Entity.
I know it's not ideal but you can always convert the allRecords.Entities inside a List of Entity and do your LINQ query against it.
Your code is probably returning an IEnumerable of Entity and not a single Entity (for example in the end of your query you can put a .ToList() to get a List of Entity.
Building on what Guido said, it is also possible to create a new EntityCollection with the results:
var matchedRecords = allRecords.Entities.Where(x => x.GetAttributeValue<EntityReference>("ccc_batchId").Id == batchId).ToList();
var matchedCollection = new EntityCollection(matchedRecords);

How to return distinct rows from and Entity with related Entities

I have an Entity that has an association to other Entities (related entities). I'm trying to return distinct rows from the primary entity which needs to include the data from the related entity so I can use one the related entity's properties downstream.
Below is the statement I'm using but it is not returning any rows. What's the best way to do this?
Below is my code.
return context.UserDisplays.Include("CurrentJob").Where(d => d.UserName == userName).GroupBy(d => d.CurrentJob.JobNo).Select(g => g.FirstOrDefault()).ToList();
Any help would be greatly appreciated!
Edit - For ComplexProperty
I believe once you do a GroupBy all Include methods are ignored. So you will need to iterate the list and call the LoadProperty method on each item. It should look something like this
var list = context.UserDisplays
.Where(d => d.UserName == userName)
.GroupBy(d => d.CurrentJob.JobNo)
.Select(g => g.FirstOrDefault()).ToList();
foreach(var item in list)
{
context.LoadProperty(item, "CurrentJob");
}
return list;
Resource Link
Check out the Distinct (Set Operators) section in this article
http://msdn.microsoft.com/en-us/vcsharp/aa336746
Are you asking for the Distinct UserDisplays? or the Distinct User or the Disticnt Jobs?
I would try say something like
var object = (from userDisplay in context.UserDisplays.Include("CurrentJob")
.Where userDisplay.UserName == userName
Select userDisplay).Distinct();
(sorry, im going off of my VB style but it should be about the same...)

LINQ to Entities multiple columns need 1 to be distinct

I am trying to select multiple columns from an entity object but I want 1 property to be distinct. I am very new to both LINQ and Entity Framework so any help will be useful.
Here is my LINQ query so far:
var listTypes = (from s in context.LIST_OF_VALUES
orderby s.SORT_INDEX
select new { s.LIST_TYPE, s.DISPLAY_TEXT });
I want s.LIST_TYPE to be distinct. I figure using the groupby keyword is what I want (maybe?) but I have not found a way to use it that works.
Thank you.
Assuming DISPLAY_TEXT matches LIST_TYPE somehow (so you don't lose any information):
var distinct = context.LIST_OF_VALUES
.OrderBy(s => s.SORT_INDEX)
.GroupBy(s => s.LIST_TYPE)
.Select(g => new { g.Key, g.First().DISPLAY_TEXT });

Differences between LINQ to Objects and LINQ to SQL queries

I have been using LINQ to query my POCO objects for some time, but I have not yet tried LINQ to SQL. I assume that LINQ to SQL queries are somehow converted to equivalent SQL queries and, given this, I am wondering if that affects the way LINQ to SQL queries are or should be written.
Are there any significant differences between LINQ to Objects and LINQ to SQL that affect how I should write a query for either?
The main difference is as you say, LINQ to SQL queries are converted into SQL. That means that there is code you can write which isn't actually convertible or has some subtly different semantics - and you only find that out at execution time.
For example:
var query = from person in people
where person.Age == person.GetHashCode()
select person;
will compile fine, but fail at execution time because LINQ to SQL doesn't know what to do with GetHashCode().
Basically I find LINQ to SQL a lot harder to predict than LINQ to Objects. That's not to say it's not useful - it's just a slightly different world. MS has done an amazing job at letting you write queries which very often just do what you expect them to, but it can't do everything.
LINQ to SQL will use the column DB server's collation for Where and OrderBy. LINQ to Objects will use string comparisons. So the former might be case-insensitive while the latter is case-sensitive. LINQ to Entities coalesces nulls. I presume L2S does the same, but I haven't tested. So in L2E you can do:
let foo = item.Property.SomeNullableType
... and foo will be null if Property is null. But in LINQ to Objects you'd have to do something like:
let foo = item.Property != null ? item.Property.SomeNullableType : null
... or you'd get a null exception.
MSDN reference here and here should help you out.
One difference that I run into is differences in grouping.
When you group in linq to objects, you get a hierarchically shaped result (keys, with child objects).
When you group in SQL, you get keys and aggregates only.
When you group in linq to sql, if you ask for the child objects (more than aggregates), linq to sql will re-query each group using the key to get those child objects. If you have thousands of groups, that can be thousands of roundtrips.
//this is ok
var results = db.Orders
.GroupBy( o => o.CustomerID )
.Select(g => new
{
CustomerId = g.Key,
OrderCount = g.Count()
});
//this could be a lot of round trips.
var results = db.Orders
.GroupBy( o => o.CustomerID )
.Select(g => new
{
CustomerId = g.Key,
OrderIds = g.Select(o => o.OrderId)
});
// this is ok
// used ToList to separate linqtosql work from linqtoObject work
var results = db.Orders
.Select(o => new {o.CustomerId, o.OrderId})
.ToList()
.GroupBy(o => o.CustomerId)
.Select(g => new
{
CustomerId = g.Key,
OrderIds = g.Select(o => o.OrderId)
});

How do dynamically set group by properties and aggregates in a LINQ query?

I assume I need to use the method call syntax instead of the query expression form, and I know the basics of grouping in the latter. Maybe some gurus can give caveats and advice on using group fields and aggregates obtained at runtime from a configuration, for use in a reporting like structure.
Have you looked at Dynamic Linq? It should do what you want. Have a look at this post from scottgu's blog.
If your data is in xml, linq to xml would allow you to write queries against it in which the certain inputs are strings.
For example:
System.Xml.Linq.XElement myData = GetData();
System.Xml.Linq.XElement result = new XElement("Result",
myData.Elements("Customer")
.GroupBy(e => e.Attributes("Name"))
.Select(g => new XElement("CustomerResult",
new XAttribute("Name" = g.Key,
new XAttribute("Count" = g.Count(),
new XAttribute("MinDate" = g.Min(e => e.Date)
)
);

Resources