NHibernate LINQ query Specified method is not supported error - c#

I am new to NHibernate and while exploring it I got into trouble with the following query which gives me a "Specified method is not supported." error, any ideas why?
var merchantSite = session.Query<MerchantSite>().FirstOrDefault(x => x.Site.Id == SiteId);
var customers = session.Query<Customer>().Where(x => x.Transaction.Any<Transaction>(y => merchantSite.Transaction.Any<Transaction>(c => c.Id == y.Id))).ToList();
Both MerchantSite and Transaction have a list of objects of type Transaction.
There must be someone out there who has been in the similar situation, please share with us your experience, what should we do in this situation?
Thanks in advance!

When you do the ToList call, that's when nHibernate is building the necessary SQL to run the query and it's basically saying that it's having trouble translating that into a single SQL call.

If x.Site is null, then you'd get "specific method is not supported." You could try writing
FirstOrDefault(x => x.Site != null && x.Site.Id == SiteId);
or using C# 6
FirstOrDefault(x => x.Site?.Id == SiteId);

Related

How can i access an object in a list in c# query with ef?

So I´m having a problem with a query im trying to do. I´m trying to get the last element of a list in a linq query in c# using ef.
Here is the code im trying to execute:
public List<Viagem> getViagensToBeCompletedInBlocoTrabalho()
{
return this.context.Viagens
.Where(v => v.blocosTrabalho.Count() == 0
|| !v.blocosTrabalho.LastOrDefault().noFim.Equals(v.horasPassagem.LastOrDefault().codigoNo)
)
.ToList();
}
But i get this error: Queries performing 'LastOrDefault' operation must have a deterministic sort order. Rewrite the query to apply an 'OrderBy' clause on the sequence before calling 'LastOrDefault'.
What am i doing wrong here?
By the way the sorting that i want is the order of entries in the table so i don´t really want to sort anything. Although i have also tested sorting and it doesn´t work.
Thanks for the help in advance :-)
Actually SQL standard do not support retrieving records from the end and even do not guarantee records in concrete order. EF is trying to simulate that by correcting OrderBy operator and if you do not specify that - it will fail.
Consider to rewrite your query and make it performant:
public List<Viagem> getViagensToBeCompletedInBlocoTrabalho()
{
var query =
from v in this.context.Viagens
from b in v.blocosTrabalho.OrderByDescending(x => x.Id)
.Take(1).DefaultIfEmpty()
from h in v.horasPassagem.OrderByDescending(x => x.Id)
.Take(1).DefaultIfEmpty()
where
b == null || b != null && b.noFim == h.codigoNo
select v;
return query.ToList();
}

LINQ expression could not be translated

I have the following database query where I am trying to check if there exists an item with a particular barcode that is linked to a particular mailbag. The query is as follows:
var exists = await dbcontext.Items
.Include(t => t.MailBagItems)
.ThenInclude(mt => mt.MailBag)
.AnyAsync(t => t.Barcode.Equals(barcode) &&
t.MailBagItems.FirstOrDefault() != null &&
t.MailBagItems.FirstOrDefault().MailBag.Number.ToLower().Equals(mailbagNumber.ToLower()));
For some reason, I'm getting the following exception:
System.InvalidOperationException: The LINQ expression could not be
translated. Either rewrite the query in a form that can be translated,
or switch to client evaluation explicitly by inserting a call to
either AsEnumerable(), AsAsyncEnumerable(), ToList(), or
ToListAsync().
I know for a fact from removing parts of the boolean expression that the issue is in the last boolean condition where I'm checking the mailbag number. However, I get the same error if I remove the calls to ToLower(). Can someone indicate what is wrong with my expression and how to fix it? Please note I'm using .NET core 3 and SQL Server.
Managed to make the query work by changing it to the following:
var exists = dbcontext.Items
.AnyAsync(t => t.Barcode.Equals(barcode) &&
t.MailBagItems.Any(t => t.MailBag.Number.ToLower().Equals(mailbagNumber.ToLower())));
Seems it wasn't enjoying the .FirstOrDefault().MailBag before.
Your AnyAsync is to complex for EF to transform to SQL, if you want to still use that query you will have to materialize the entities first, like this:
var exists = dbcontext.Items
.Include(t => t.MailBagItems)
.ThenInclude(mt => mt.MailBag)
.ToListAsync()
.AnyAsync(t => t.Barcode.Equals(barcode) &&
t.MailBagItems.FirstOrDefault() != null &&
t.MailBagItems.FirstOrDefault().MailBag.Number.ToLower().Equals(mailbagNumber.ToLower()));
Also you are missing the await keyword, or was that intended?

What will be the equivalent sql query for this code?

This code is giving inaccurate results and I need to change it but I do not understand what the whole code is doing.
I read about defaultifempty and its implementation. I read the documentation but I could not find the answer to the question.
var records = from entity in _db.InventoryDetails
from am in _db.AccountMeters
.Where(am => entity.SerialNumber == (am.SerialNumber ?? am.RemoteId.ToString())).DefaultIfEmpty()
from ac in _db.Accounts
.Where(ac => ac.AccountId == am.AccountId).DefaultIfEmpty()
from i in _db.Inventories
.Where(idd => idd.ProjectId == projectid)
.Where(idd => idd.InventoryId == entity.InventoryId)
from u in _db.Users
.Where(e => e.Id == (entity.InstallerId ?? entity.PrevInstaller)).DefaultIfEmpty()
It does not give error just the query is giving wrong result. If I can find sql equivalent for the code then I can find out what he was trying to do and then find out business requirement and re code.
You can get SQL code which will be generated by your code through calling ToString() method:
var records = from entity in _db.InventoryDetails
// the other code is omitted for the brevity
var sqlCode = records.ToString(); // here your generated SQL code
With EF 6 and beyond, you can use
context.Database.Log = Console.Write;
to write the SQL to the console.

Linq Exception: Function can only be invoked from linq to entities

I have a StudentReceipts table which stores ReceiptNo as string(001,002,003,..,099,..).
I want go get the last receiptno details inorder to increment the receiptno for next transaction.
This is what I have tried
var _lastGeneratedRecDetails = _db.StudentReceipts
.AsEnumerable()
.Where(r => r.Status == true
&& EntityFunctions.TruncateTime(r.DueDate.Value) >= _startDate.Date
&& EntityFunctions.TruncateTime(r.DueDate.Value) <= _endDate.Date)
.OrderByDescending(x => Int32.Parse(x.ReceiptNo))
.FirstOrDefault();
But there i am getting the following exception
this function can only be invoked from linq to entities
Any help will be highly appreciated.
By calling .AsEnumerable() you are going from Linq-To-Entities to Linq-To-Object. By calling it, you are also filtering all the results in memory, so you are pulling the whole StudentReceipts table from the database everytime you do that query as it gets executed past the .AsEnumerable() method. The general rule is to try to do as much as you can on the database side:
var _lastGeneratedRecDetails =
_db.StudentReceipts.Where(r => r.Status == true
&& EntityFunctions.TruncateTime(r.DueDate.Value) >= _startDate.Date
&& EntityFunctions.TruncateTime(r.DueDate.Value) <= _endDate.Date)
.AsEnumerable()
.OrderByDescending(x => Int32.Parse(x.ReceiptNo))
.FirstOrDefault();
If you do it like this, you will filter everything in the database and fetch the filtered results. I don't know what type x.ReceiptNo is though, but calling Int.Parse isn't allowed in Linq-To-Entities. You can filter first and then call AsEnumerable to be able to do the parsing and ordering in memory.
In my case, I was re-using a Func / Filter expression that included DbFunctions.TruncateTime in a follow-up processing statement AFTER I had already processed the query in SQL. Removing it cleared the instance of the exception for me.
use and
.AsQueryable()
var _lastGeneratedRecDetails = _db.StudentReceipts
.AsEnumerable().AsQueryable()

LINQ - "Unable to create constant value of type [type]"?

Here's my error
Unable to create a constant value of type 'Courses.Model.Track'. Only primitive types or enumeration types are supported in this context.
and here's the code that causes it:
model.Courses = db.Courses
.Where(c => model.Tracks.Any(t => t.Certification.ID == certificate))
.ToList();
Also, model.Courses is IEnumerable<Courses>, and I'm not sure if that has anything to do with my problem.
Could anybody shed some light on this for me? Many thanks.
db.Courses is an IQueryable. While the syntax is virtually identical to the LINQ methods of IEnumerable, under the hood they're completely different.
The IQueryable code isn't actually exectued anywhere at all. It just creates a bunch of Expression objects that different query providers are able to use to do...whatever they want (in this case query a database). Those query providers need to specifically have code to handle any given type of input. There are some things that they either can't sensibly transform into a SQL query, or things that the programmers simply didn't think of or choose to handle (even if it might have a sensible SQL translation).
In sort, the query provider just doesn't know how to translate model.Tracks.Any(t => t.Certification.ID == certificate) into SQL.
You simply need to know what types of code is and isn't supported by the query provider that you're using and try to manipulate the code you have into something that it can handle. Something like this should work:
var certificates = model.Tracks.Select(t => t.Certification.ID).ToList();
model.Courses = db.Courses
.Where(c => certificates.Contains(c))
.ToList();
If this were C# code executing all of this in LINQ to objects the two queries would be identical, but to a query provider they're not. They simply have special support for knowing when they see List.Contains to map it to a SQL IN clause. They didn't add specific support for what you did in your first query.
Try using LINQ 'Where In', this should solve your problem:
var names = new string[] { "Alex", "Colin", "Danny", "Diego" };
var matches = from person in people
where names.Contains(person.Firstname)
select person;
OR
var matches = from person in people
where person.Firstname == "Alex" ||
person.Firstname == "Colin" ||
person.Firstname == "Danny" ||
person.Firstname == "Diego"
select person;
http://blogs.msdn.com/b/alexj/archive/2009/03/26/tip-8-writing-where-in-style-queries-using-linq-to-entities.aspx
My apologies for the almost unnecessary question, although #klugerama did help me figure it out.
There was a problem with this:
model.Courses = db.Courses
.Where(c => model.Tracks.Any(t => t.Certification.ID == certificate))
.ToList();
Until I changed it to this:
model.Courses = db.Courses
.Where(c => c.Track.Certification.ID == certificate)
.ToList();
Again, my apologies. Thanks to everyone for their input.

Categories