Enumeration yielded no result? - linq

I am trying to filter some objects using linq to enitites and I get an error telling me "Enumeration yielded no results".
on the client side I get a message like this:
The operation cannot be completed because the DbContext has been
disposed
I know that these filter values should return some results but it just doesnt work, so Im guessing my query is wrong, can you help please.
var mediaChannels =
NeptuneUnitOfWork.MediaChannels
.FindWhere(m => m.CountryID == CountryID &&
m.SonarMediaTypeID == MediaTypeID &&
m.SonarMediaTypes.SonarMediaGroupID == MediaGroupID &&
m.Name.Contains(search))
.Select(m => new MediaChannelModel() {
ID = m.ID,
Name = m.Name,
MediaType = m.MediaType.Name,
Country = m.Countries.Name,
SubRegion = m.Countries.Lookup_SubRegions.Name,
Region = m.Countries.Lookup_SubRegions.Lookup_Regions.Name
});

My guess is that this runs just fine, then you dispose you context, then you try to access mediaChannels. The problem is that Linq uses deferred execution. Therefore, you query doesn't really execute until you enumerate mediaChannels, which is after you context is disposed.
If you don't want to use deferred execution, then add a .ToList() to the end of your query to force it to load right there.
If you want to use deferred execution, then you can't dispose of your context until a later point.

The operation cannot be completed because the DbContext has been disposed is often seen if you send data to the client without saving the data to memory. This can be easily fixed by .ToList()-ing your query before sending it to the page
var mediaChannels = NeptuneUnitOfWork.MediaChannels
.Where(m => m.CountryID == CountryID
&& m.SonarMediaTypeID == MediaTypeID &&
&& m.SonarMediaTypes.SonarMediaGroupID == MediaGroupID
&& m.Name.Contains(search))
.Select(m => new MediaChannelModel() {
ID = m.ID,
Name = m.Name,
MediaType = m.MediaType.Name,
Country = m.Countries.Name,
SubRegion = m.Countries.Lookup_SubRegions.Name,
Region = m.Countries.Lookup_SubRegions.Lookup_Regions.Name
}).ToList(); // <<-- NOTE this additional method

Related

Retrieve single element from LINQ query

Working with LINQ for the first time in a while and trying to clean something up. I have the following statements:
var element = await _Entities.References
.Where(db => db.LoadId == request.LoadId && db.ReferenceCode == "123")
.OrderByDescending(rec => rec.Created).FirstOrDefaultAsync(cancellationToken);
if (element != null) {
dto.ElementValue = element.Value;
}
I'd like to condense this into a single statement if possible but I was having trouble getting just the value from the await method.
You could do something like this:
dto.ElementValue = (await _Entity.References
.Where(db => db.LoadId == request.LoadId && db.ReferenceCode == "123")
.OrderByDescending(rec => rec.Created)
.FirstOrDefaultAsync(cancellationToken))?.Value
?? dto.ElementValue;
Note that technically this changes the behaviour of the code. Previously, if the query doesn't return a result, the ElementValue property is not touched. With a one-liner, if the query doesn't return a result, the ElementValue getter and setter will both be called.
Also, if the query returns a result whose Value is null, the ElementValue property will be set to itself rather than null.

LINQ to Entities does not recognize the method 'Boolean HasFlag(System.Enum)' method, and this method cannot be translated into a store expression

I have this service:
//seroiunoiweucroewr
///wercewrwerwerwer
//wcererewrwerwer
public List<UserRoleContract> GetRolePagesByUserId(long plngUserId, DisplayType displayType)
{
List<UserRoleContract> result = new List<UserRoleContract>();
using (CitiCallEntities context = new CitiCallEntities())
{
try
{
//var DisplayList = Utility.GetEnumDescriptions(typeof(DisplayType)).ToList();
//var selectValue = DisplayList.Where(i => i.Key == (byte) DisplayType.Windows).FirstOrDefault();
result = (from oUser in context.User
join oUserRole in context.UserRole on oUser.Id equals oUserRole.UserId
join oRoleRightsPage in context.RoleRightsPage.Where(i => i.IsActive == true)
on oUserRole.RoleId equals oRoleRightsPage.RoleId
join oApplicationPage in context.ApplicationPage.Where(i => i.IsActive == true)
on oRoleRightsPage.PageId equals oApplicationPage.Id
join oRole in context.Role on oUserRole.RoleId equals oRole.Id
join oEmployee in context.Employee on oUser.EmployeeId equals oEmployee.Id
join oSection in context.Section on oEmployee.SectionId equals oSection.Id
where oUser.IsActive == true && oUser.Id == plngUserId
&& oRole.IsActive == true && (((DisplayType)oRoleRightsPage.DisplayType).HasFlag(displayType))
//am getting error in has flag
// am having three display type web, windows and all
// how to overcome
select new UserRoleContract
{
UserId = oUser.Id,
RoleId = oRole.Id,
RoleName = oRole.RoleName,
PageID = oApplicationPage.Id,
PageName = oApplicationPage.PageName,
IsOPsCtrl = oRole.IsOPsCtrl,
ISOPsCtrlFor = oRole.OPsCtrlFor,
SectionId = oSection.Id,
DisplayType = oRoleRightsPage.DisplayType,
}).Distinct().ToList();
}
catch (Exception exception)
{
HandleExpcetion(exception);
//throw new CitiCallException(exception.Message);
}
}
return result;
}
I am getting Linq error in has flag conversion, how do I overcome this problem?
you are geeting error because HasFlag method is not paresent in database i.e. it might be part of language or local function in code which is not present in database.
So when query is translated it found this method is not available and that is the reason you are getting error.
one solution to avoid this error is
Brind all data from databae
Than filter than data, i.e. apply HasFlag method of it.
But this will bring all data and might decrease performance.
Example is
remove this line (((DisplayType)oRoleRightsPage.DisplayType).HasFlag(displayType) from your query
var list = querieddata //first fetch data without hasflag condition/method
.AsEnumerable() // Rest of the query in-process
.Where(oRoleRightsPage=> ((DisplayType)oRoleRightsPage.DisplayType).HasFlag(displayType))//apply condition here once fetching done
.ToList();
The HasFlag method has no equivalent in Linq to Entities which is why you get that error. You can get around it by using bitwise comparison instead of using HasFlag, for example this:
((DisplayType)oRoleRightsPage.DisplayType).HasFlag(displayType)
Becomes:
(oRoleRightsPage.DisplayType & displayType) > 0

NotSupportedException thrown after call to .AsEnumerable()

I have some simple code that retrieves recorded ELMAH exceptions from a db:
HealthMonitoringEntities context = new HealthMonitoringEntities();
IQueryable<ELMAH_Error> exceptions = context.ELMAH_Error;
if (filter.ToDate != null)
exceptions = exceptions.Where(e => e.TimeUtc <= filter.ToDate.Value.AddHours(-4));
return exceptions.OrderByDescending(e => e.TimeUtc)
.Take(filter.Size)
.AsEnumerable()
.Select(e => new ElmahException()
{
ErrorId = e.ErrorId,
Application = e.Application,
Host = e.Host,
Type = e.Type,
Source = e.Source,
Error = e.Message,
User = e.User,
Code = e.StatusCode,
TimeStamp = e.TimeUtc.AddHours(-4).ToString()
}).ToList();
}
I get an exception on this line:
TimeStamp = e.TimeUtc.AddHours(-4).ToString()
The exception is:
LINQ to Entities does not recognize the method 'System.DateTime AddHours(Double)' method, and this method cannot be translated into a store expression.
When I call .AsEnumerable() before projecting with Select(), my sequence is enumerated and I project from a sequence that implements IEnumerable<ELMAH_Error>. Given that, why am I not working with the Linq-To-Objects API in my projection, which understands AddHours(), instead of still working with the Linq-To-Entities API?
UPDATE
There is a post on this topic by Jon Skeet here:
http://msmvps.com/blogs/jon_skeet/archive/2011/01/14/reimplementing-linq-to-objects-part-36-asenumerable.aspx
He has this query:
var query = db.Context
.Customers
.Where(c => some filter for SQL)
.OrderBy(c => some ordering for SQL)
.Select(c => some projection for SQL)
.AsEnumerable() // Switch to "in-process" for rest of query
.Where(c => some extra LINQ to Objects filtering)
.Select(c => some extra LINQ to Objects projection);
Note that after his call to AsEnumerable(), he indicated he is switching over to Linq-To-Objects. I am doing something similar in my function, but I am receiving a Linq-To-Entities exception where I had thought I would be executing against the Linq-To-Objects API.
Further Update
From Jim Wooley's blog: http://linqinaction.net/blogs/jwooley/archive/2009/01/21/linq-supported-data-types-and-functions.aspx
"As an example the following methods are shown as having translations for DateTime values: Add, Equals, CompareTo, Date, Day, Month, Year. In contrast methods like ToShortDateString, IsLeapYear, ToUniversalTime are not supported.
If you need to use one of the unsupported methods, you need to force the results to the client and evaulate them using LINQ to Objects at that point. You can do that using the .AsEnumerable extension method at any point in the query comprehension."
Is that not what I'm doing?
You have forgotten to protect your first call
if (filter.ToDate != null)
exceptions = exceptions.AsEnumerable()
.Where(e => e.TimeUtc <= filter.ToDate.Value.AddHours(-4));
Edit
Remember, IQueryables are not translated to sql until they are enumerated, so your debugger will execute that line but the error won't occur until you return. If filter.ToDate is null your code is equivalent to this:
if(filter.ToDate == null)
return exceptions
.Where(e => e.TimeUtc <= filter.ToDate
.Value
.AddHours(-4)) //uh-oh won't work in Linq-to-Entities
.OrderByDescending(e => e.TimeUtc)
.Take(filter.Size)
.AsEnumerable() //too late to protect you!
.Select(e => new ElmahException()
{
ErrorId = e.ErrorId,
Application = e.Application,
Host = e.Host,
Type = e.Type,
Source = e.Source,
Error = e.Message,
User = e.User,
Code = e.StatusCode,
TimeStamp = e.TimeUtc.AddHours(-4).ToString() //if we get this far we're OK
}).ToList();

executeQueryLocally does not work well when using withParameters

I'm trying to use executeQueryLocally in a query that has 'withParamters', but it seems that I get locally cached data even when using new values in the 'withParameters'. It is as if 'executeQueryLocally' ignores values in 'withParameters'.
here is the code in the client side:
var query = EntityQuery.from('ProductsFilteredByCategory')
.withParameters({ categoryId: categoryId })
.select("productId,name,desc,shopPrice,webPrice")
.orderBy('name');
var p = manager.executeQueryLocally(query);
if (p.length > 5) {
productsObservable(p);
return Q.resolve();
}
here is the code for 'ProductsFilteredByCategory' on the server side:
[HttpGet]
public IQueryable<Product> ProductsFilteredByCategory(int categoryId)
{
Category category = _contextProvider.Context.Categories.Include("Products").Include("SubCategories").First(c => c.CategoryId == categoryId);
var prods = from p in category.Products select p;
category.SubCategories.ForEach(sc => prods = prods.Concat(_contextProvider.Context.Categories.Include("Products").First(c => c.CategoryId == sc.CategoryId).Products));
return prods.AsQueryable();
}
what happens is that after I retrieve the data once with 'p.length > 5' being true, in every subsequent call 'p.length > 5' is still true even when 'categoryId' is different, so the data that is bound to the observable is loaded once and never changes.
Thanks for your help !
Elior
The EntityQuery.withParameters method is NOT intended for local query use. (We should probably document this better).
WithParameters sends application domain specific parameters that can only be interpreted on the server. Unlike with 'where', 'orderBy', 'take' etc, there is no global interpretation that can be determined for a withParameters call. It can only be understood within the context of the server side method that accepts the parameters.

if-else clause in Linq to entity framework query

Following Linq to Entities query is causing the "Unable to create a constant value of type 'Data.InhouseUnit'. Only primitive types ('such as Int32, String, and Guid') are supported in this context" exception.
IList<FaultReport> faultReports = (from fr in _session.FaultReports
where fr.CreatedOn > dateTime
select new FaultReport
{
Id = fr.Id,
ExecutionDate = fr.ExecutionDate ?? DateTime.MinValue,
FaultType = fr.FaultType,
Quarters = fr.Quarters,
InhouseSpaceId = fr.InhouseSpaceId,
InhouseSpace = new InhouseSpace { Id = fr.InhouseSpace.Id, Name = fr.InhouseSpace.Name },
InhouseUnitId = fr.InhouseUnitId ?? Guid.Empty,
**InhouseUnit = fr.InhouseUnitId == Guid.Empty ? null : new InhouseUnit { Id = fr.InhouseUnit.Id, Name = fr.InhouseUnit.Name }**
}).ToList();
Specifically, it is the if expression in bold font which causes the exception. I need to make the check as fr.InhouseUnitId is a nullable. If I take out the the bolded expression, the rest of the statement works just fine. I have spent a fair amount of time, in msdn forum and on web, to understand what is causing the exception but still cannot quite understand. Guid is scalar so it should work, right? Even this expression InhouseUnit = true ? null: new InhouseUnit() in place of the bolded expression in the above statement wouldn't work. Can we even write if/else
If i try to write an extension method to take away the logic and just return a result, following exception is thrown:
LINQ to Entities does not recognize the method 'System.Object
GuidConversion(System.Nullable`1[System.Guid], System.Object)' method, and this method
cannot be translated into a store expression
It looks like you are projecting into new objects of the same type that you are querying from. Is that the case? It seems a little weird, but assuming you have a good reason for doing this, you could split the query into two parts. The first part would get what you need from the database. The second part would run locally (i.e. LINQ-to-Objects) to give you the projection you need. Something like this:
var query =
from fr in _session.FaultReports
where fr.CreatedOn > dateTime
select new {
fr.Id,
fr.ExecutionDate,
fr.FaultType,
fr.Quarters,
InhouseSpaceId = fr.InhouseSpace.Id,
InhouseSpaceName = fr.InhouseSpace.Name,
InhouseUnitId = fr.InhouseUnit.Id,
InhouseUnitName = fr.InhouseUnit.Name,
};
IList<FaultReport> faultReports = (
from fr in query.ToList()
select new FaultReport {
Id = fr.Id,
ExecutionDate = fr.ExecutionDate ?? DateTime.MinValue,
FaultType = fr.FaultType,
Quarters = fr.Quarters,
InhouseSpaceId = fr.InhouseSpaceId,
InhouseSpace = new InhouseSpace { Id = fr.InhouseSpaceId, Name = fr.InhouseSpaceName },
InhouseUnitId = fr.InhouseUnitId ?? Guid.Empty,
InhouseUnit = fr.InhouseUnitId == Guid.Empty ? null : new InhouseUnit { Id = fr.InhouseUnitId, Name = fr.InhouseUnitName }
}).ToList();

Resources