NH Linq with FetchMany and ToFutureValue in NH 3.0.0beta - linq

I'm trying to use the ToFuture with the new NH Linq 3.0 provider.
This works fine:
var result = ses.Query<Parent>()
.Where(x => x.Id == id)
.ToFutureValue();
but when I use a Fetch/FetchMany like this:
var result = ses.Query<Parent>()
.Where(x => x.Id == id)
.Fetch(x => X.Child)
.ToFutureValue();
This exception occurs:
NotSupportedException with: You can
also use the AsFuture() method on
NhQueryable
Any suggestions?

It's probably not implemented yet (LINQ Futures is one of the most recently added features, just a few weeks ago).
You can enter an issue at http://jira.nhforge.org/

.Fetch(x => X.Child)
return IQueryable<>, not NhQueryable<>
that's why we got exception
Take a look:
http://www.symbolsource.org/Public/Metadata/Default/Project/NHibernate/3.0.0.GA/Release/All/NHibernate/NHibernate/Linq/LinqExtensionMethods.cs

Related

How to update context in EF Core without ForEach?

I am getting some data from my database:
var productCollections = _context.ProductCollections
.Include(pc => pc.Products)
.ThenInclude(p => p.ProductDetails)
.FirstOrDefault(x => x.Id == productCollectionId);
With the products in the collection I am getting some product-details from a different backend and safe that data in a List<> containing the product-number and the details. I want to add these details to a List<> named ProductDetails in the products.
productCollection.Products.ForEach(p => p.ProductDetails.AddRange(
foundProductDetailsList
.Where(d => d.RequestedProductNumber == p.ProductNumber)
.Select(x => new StaticPartBasketItemFound
{
DetailX = x.DetailX,
DetailY = x.DetailY
})));
Both may contain 100.000 items and it's pretty slow to perform the code above.
Is there any chance to "join-update" the "ProductDetails" within my "productCollection.Products" or similar fast methods?
I am using .NET 5.0.3 and EF-Core.

FirstOrDefault throws ArgumentnullException

My goal is to extract a specific record that has a parameter value specified by me. The data is taken from an external API.
My query looks like this:
var productId = productsResponse.Where(x => x.Parameters.Any(y => y.Values.Any(z => z.Equals(auctionTitle)))).FirstOrDefault();
And it works fine until where filters out all the records. Then the method aborts and debugging cannot continue.
The problem is:
System.ArgumentNullException: Value cannot be null
because source transferred to FirstOrDefault is null.
I also tried:
var productId = productsResponse.Where(x => x.Parameters.Any(y => y.Values.Any(z => z.Equals(auctionTitle)))).DefaultIfEmpty().First();
Please let me know what topic I should read because I have run out of ideas. I really care to understand where I am wrong.
This can be not an answer but try this construction:
var productId = productsResponse
.Where(x => x.Parameters.SelectMany(y => y.Values)
.Any(z => z == auctionTitle))
.FirstOrDefault();
Also if data came from external API, it may be needed more null check.
var productId = productsResponse
.Where(x => x.Parameters?.SelectMany(y => y.Values ?? Enumerable.Empty<Value>())
?.Any(z => z == auctionTitle) == true)
.FirstOrDefault();

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();

could not resolve property (complex properties)

I have a asp.net mvc application with NHibernate and I do not know how to resolve a problem to query some data. I have this query:
// create query
var query = session.QueryOVer<Laudo>().Fetch(x => x.Equipament).Eager;
// add some filters
if (idEquipament.HasValue)
query = query.And(x => x.Equipament.Id == idEquipament.Value);
//I got the error here...
if (idCompany.HasValue)
query = query.And(x => x.Equipament.Company.Id == idCompany.Value);
When I try to execute this query, I've got an exception with this message:
"could not resolve property: Equipament.Company.Id of: DomainModel.Laudo"
what can I do to fix this problem?
Thanks
You cannot use another entity property like that. NHibernate expects expression that can be evaluated to property of the current entity. You need to use JoinQueryOver or JoinAlias to join another entity, and perform where after that.
With JoinQueryOver:
// ...
query = query.JoinQueryOver(x => x.Equipment)
.JoinQueryOver(x => x.Company)
.Where(c => c.Id == idCompany.Value);
With JoinAlias:
Equipment equipment = null;
Company company = null;
// ...
query = query.JoinAlias(x => x.Equipment, () => equipment)
.JoinAlias(() => equipment.Company, () => company)
.Where(() => company.Id == idCompany.Value);
Some more info:
What is the difference between JoinQueryOver and JoinAlias?
What can be used as a NHibernate QueryOver alias?
Complex nHibernate QueryOver expression
The tags chosen for your question make me think you didn't want to use QueryOver, but LINQ.
This is achieved by using the extension method Query, in the NHibernate.Linq namespace:
var query = session.Query<Laudo>().Fetch(x => x.Equipament);
if (idEquipament.HasValue)
query = query.Where(x => x.Equipament.Id == idEquipament.Value);
if (idCompany.HasValue)
query = query.Where(x => x.Equipament.Company.Id == idCompany.Value);

How to include related objects in grouped Entity LINQ queries?

I have some Setting entities that are related to a SettingDescription which is related to a SettingGroup.
Setting history is preserved by making a "Modified" field part of the key.
To get the settings matching a specific category I use this query (after help from here):
var latestSettings =
context.Settings.Include("Description.SettingGroup")
.OrderByDescending(x => x.Modified)
.GroupBy(x =>
new {
x.Category,
x.Group,
x.Name,
x.Target }, x => x)
.Where(x => x.Key.Category == category)
.Select(result => result.FirstOrDefault())
.ToArray();
This returns a set of the latest settings, but the "Include" part is completely ignored. However, I can force load the descriptions by running a second dummy query that loads the descriptions into the context.
var latestSettings =
context.Settings.Include("Description.SettingGroup")
.OrderByDescending(x => x.Modified)
.GroupBy(x =>
new {
x.Category,
x.Group,
x.Name,
x.Target }, x => x)
.Where(x => x.Key.Category == category)
.Select(result => result.FirstOrDefault())
.ToArray();
var settingDescriptions =
context.SettingDescriptions.Include("SettingGroup")
.Where(x => x.Category == category)
.ToArray();
Why is the include ignored in the "stand alone" group query?
Can I combine the setting and description loading into a single query?
AlexJ from the EF team posted an excellent series of tips, including:
"Tip 22 - How to make Include really Include"
http://blogs.msdn.com/b/alexj/archive/2009/06/02/tip-22-how-to-make-include-really-include.aspx
It looks to me like your query is returning "Settings" entities (without a "change of shape") so this tip should apply.

Resources