Linq GroupBy how to return a collection of objects that are grouped into another list? - linq

I'm having a difficult time trying to return a collection of objects after I use Linq to do a GroupBy on the collection.
The specifics are, I have a collection of CurrentSegmentGroupDetail objects being returned when I call a view from EF 4.1. Using a Lambda expression, I group the CurrentSegmentGroupDetail object by a SegmentGroup property. The result I get is a list of SegmetGroups that contain CurrentSegmentGroupDetail objects. The problem I'm having is trying to return the grouped result set back to a type of List.
Here is the code I have so far:
public List<CurrentSegmentGroupDetail> GetSegmentGroupsForReconciliation()
{
using (var context = new PricingContext())
{
var segmentGroups =
context.CurrentSegmentGroupDetails.GroupBy(s => s.SegmentGroup).Select(y => y);
return segmentGroups;
}
}
Here is the exception I'm getting when I try and pass the result set into my List object:
"Cannot implicitly convert type 'System.Linq.IQueryable>' to 'System.Collections.Generic.List'.
I would greatly appreciate any help on this.

ToList()
return segmentGroups.ToList();

Related

Will you get the benefits of IQueryable if you use entity projections?

Lets say I have a method like this:
IQueryable<MyFlatObject> GetMyFlatObjects()
{
using (var context = new MyEntities())
{
return context.MyEntities.Select(x => new MyFlatObject()
{
Property1 = x.PropertyA,
Property2 = x.PropertyB,
Property3 = x.PropertyC,
});
}
}
Now if I call:
MyService.GetMyFlatObjects().Where(x => x.Property1 == "test");
Sanity check. This filter will not propagate to my database store (like if I had just queried my entities), but instead I will get all results back and be using LINQ-to-objects to filter. Right?
I think, it's not right. First, it doesn't query anything because you are only extending an IQueryable<T> to a new IQueryable<T>. If you call ToList() or anything else that causes the query to execute you'll get an exception because the context has already been disposed at the end of the using block. If you don't dispose the context the Where filter will be translated to SQL and executed in the database. I believe it will behave the same way as if you would apply the Where to PropertyA before the Select.

LINQ to Entities does not recognize the method 'Boolean CheckMeetingSettings(Int64, Int64)' method

I am working with code first approach in EDM and facing an error for which I can't the solution.Pls help me
LINQ to Entities does not recognize the method 'Boolean
CheckMeetingSettings(Int64, Int64)' method, and this method cannot be
translated into a store expression.
My code is following(this is the query which I have written
from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
}
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
Please help me out of this.
EF can not convert custom code to SQL. Try iterating the result set and assigning the property outside the LINQ query.
var people = (from per in obj.tempPersonConferenceDbSet
where per.Conference.Id == 2
order by /**/
select new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
}).Skip(/*records count to skip*/)
.Take(/*records count to retrieve*/)
.ToList();
people.ForEach(p => p.CanSendMeetingRequest = CheckMeetingSettings(6327, p.Id));
With Entity Framework, you cannot mix code that runs on the database server with code that runs inside the application. The only way you could write a query like this, is if you defined a function inside SQL Server to implement the code that you've written.
More information on how to expose that function to LINQ to Entities can be found here.
Alternatively, you would have to call CheckMeetingSettings outside the initial query, as Eranga demonstrated.
Try:
var personDetails = obj.tempPersonConferenceDbSet.Where(p=>p.ConferenceId == 2).AsEnumerable().Select(p=> new PersonDetials
{
Id = per.Person.Id,
JobTitle = per.Person.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327,per.Person.Id)
});
public bool CheckMeetingSettings(int,int)
{
///code I have written.
}
You must use AsEnumerable() so you can preform CheckMeetingSettings.
Linq to Entities can't translate your custom code into a SQL query.
You might consider first selecting only the database columns, then add a .ToList() to force the query to resolve. After you have those results you van do another select where you add the information from your CheckMeetingSettings method.
I'm more comfortable with the fluid syntax so I've used that in the following example.
var query = obj.tempPersonConferenceDbSet
.Where(per => per.Conference.Id == 2).Select(per => new { Id = per.Person.Id, JobTitle = per.Person.JobTitle })
.ToList()
.Select(per => new PersonDetails { Id = per.Id,
JobTitle = per.JobTitle,
CanSendMeetingRequest = CheckMeetingSettings(6327, per.Person.Id) })
If your CheckMeetingSettings method also accesses the database you might want to consider not using a seperate method to prevent a SELECT N+1 scenario and try to express the logic as part of the query in terms that the database can understand.

Convert Loop To Linq - Model Creation

I'm converting an entity object to a model that can be passed around my application without the extra overhead (As well as generating a couple of extra fields for the view etc.
public IEnumerable<PageModel> GetAllPages()
{
var AllPageO = _session.All<Page>();
IList<PageModel> RetO = new List<PageModel>();
foreach (var AP in AllPageO)
{
RetO.Add(new PageModel(AP));
}
return RetO.AsEnumerable();
}
Can this be converted to a Linq Query, the below does work I get the error
Server Error in '/' Application. Only
parameterless constructors and
initializers are supported in LINQ to
Entities.
public IEnumerable<PageModel> GetAllPages()
{
var AllPageO = _session.All<Page>();
var RetO = from EntityO in AllPageO select new PageModel(EntityO);
return RetO;
}
Resharper actually converts the firt loop into this, which also fails with the same error.
IList<PageModel> RetO = PageO.Select(AP => new PageModel(AP)).ToList();
Thats because entity framework is trying to convert optimize your projection expression into sql.
The easy fix is to enumerate the results before the projection:
var RetO = from EntityO in AllPageO.ToList() select new PageModel(EntityO);

Converting Foreach Loop to Linq and getting error

I've currently got the following foreach loop:
List<SearchResult> searchResults = new List<SearchResult>();
foreach (Transmission trans in Results)
{
searchResults.Add(new SearchResult(trans));
}
return searchResults;
And I'd like to convert this to a Linq expression, I've tried the following which looks like it achieve the same thing in linq to me:
return Results.Select(x => new SearchResult(x)).ToList();
However when executed I get the following error:
System.InvalidCastException: Object must implement IConvertible.
I think I understand the gist of that error but the issue I have is that I'm not actually trying to convert the Transmission Objects in the Results collection to SearchResult objects but instead to return a list of SearchResult objects, a SearchResult object being intialized like so:
Transmission transmission = new Transmission(...);
SearchResult result = new SearchResult(trans);
Any help on this would be great, I've been tearing my hair out!
EDIT: As per comments here is the full method stub:
public IQueryable<Transmission> Results
{
get;
set;
}
public virtual IEnumerable<SearchResult> ResultsNetwork
{
get
{
List<SearchResult> searchResults = new List<SearchResult>();
foreach (Transmission trans in Results)
{
searchResults.Add(new SearchResult(trans));
}
return searchResults;
}
}
I get the impression that Results is a collection of object, so Select is defining x as object, but you want it to be Transmission.
Try either of these options:
return Results.Cast<Transmission>().Select(x => new SearchResult(x)).ToList();
return Results.OfType<Transmission>().Select(x => new SearchResult(x)).ToList();
Cheers.
Its hard to guess what you are trying to cast (you need to show your method signature, as well as a blurb showing how you convert Transmissions to SearchResult)
However and easier way to do it:
return Results.ConvertAll(x=> new SearchResult(x));

When selecting an anonymous type with LINQ from EF, is there no way to run a method on an object as you select it?

Let's say I have a method:
bool myMethod(int a)
{
//return a bool
}
So let's say I the following
// assume a has prop1 and prop2 both ints
var mySelection = from a in myContainer
where a=somecondition
select new {
a.prop1,
myMethod(a.prop2)
};
Is there really no way to run myMethod in the anonymous type declaration? Is there some sort of trick?
Can I put an anonymous method in there to return the equivalent of myMethod(a.prop2)?
Well lets separate this into LINQ to Objects and LINQ to Entities
In LINQ to Object the above fails because the compiler doesn't know what the Property name is, if you change it to this:
var mySelection = from a in myContainer
where a=somecondition
select new {
a.prop1,
prop2 = myMethod(a.prop2)
};
It will work in LINQ to Objects
However the Entity Framework won't be able to translate the method call (unless it is a function known to the EF like a Model Defined Function, EdmMethods or SqlMethods) so you'll have to rewrite that query like this:
var mySelection = from a in myContainer
where a=somecondition
select new {
a.prop1,
a.prop2
};
var myResults = from a in mySelection.AsEnumerable()
select new {a.prop1, prop2 = myMethod(a.prop2)};
This pulls what you need out the database, and then using the AsEnumerable() call turns the call to myMethod into something processed by LINQ to Objects rather than LINQ to Entities
Hope this helps
Alex
I don't think there is a way to call out to a method from an anonymous initializer. Even if there were, it probably wouldn't perform very well.
If you need to create a result set that requires additional processing, I would create a concrete class.

Resources