LINQ query stops working after adding 'Orderby' clause - c#

I have a working linq query as follows:
public static List<Coins> GetAllCoins(string typeselected)
{
using (var db = new SQLiteConnection(DbPath))
{
List<Coins> allcoins = (from p in db.Table<Coins>()
where p.CoinType== typeselected
// orderby p.YearMinted
select p
).ToList();
return allcoins;
}
}
I want to get the results in order but when I uncomment the 'orderby' line, the query returns nothing. What's up with that?
I have checked the syntax many times. I have queried online for linq query format and I find many instances where the orderby clause is used in this manner. I know I'm missing something but I can't figure what. Please help!

Related

Entity Framework, Repository pattern and let statements

Trying to implement a correct Repository pattern with Entity Framework, I'm stumbling over some issues with let statements. What I want to do is:
var customer = (from cus in Customers.GetAll()
let brokerExists = InsuredBrokers.GetAll().Any(ib => ib.INS_Id == cus.INS_Id)
// ... more stuff
But this will give me an error
System.NotSupportedException: 'LINQ to Entities does not recognize the
method
'System.Linq.IQueryable`1[SNIP.DataModel.EA_INB_InsuredBrokers_TB]
GetAll()' method, and this method cannot be translated into a store
expression.'
What I instead can do is:
var customer = (from cus in Customers.GetAll()
let brokerExists = _context.Set<EA_INB_InsuredBrokers_TB>().Any(ib => ib.INS_Id == cus.INS_Id)
// ... more stuff
However, this breaks any point in using the Repository pattern. When I search for answers, people say to put it in a query on its own and reference it from memory, but since I actually have the customer's Id (INS_Id) in the let statement, I cannot do that.
GetAll() is like:
public IQueryable<T> GetAll()
{
return _context.Set<T>().AsQueryable();
}
Are there any clever ways to get around this?
You have to move InsuredBrokers.GetAll() out of the query:
var allBrokers = InsuredBrokers.GetAll();
var customer = (from cus in Customers.GetAll()
let brokerExists = allBrokers.Any(ib => ib.INS_Id == cus.INS_Id)
// ... more stuff
Then it will work fine. Since GetAll returns IQueryable and you don't enumerate it - this has no negative effect and there will still be one query to database, just like in your example with _context.
The reason is let statement is compiled like this:
Customers.GetAll().Select(cus => new {cus, brokerExists = InsuredBrokers.GetAll().Any(ib => ib.INS_Id == cus.INS_Id)}
Which means your call to InsuredBrokers.GetAll() is part of expression tree (it's inside Select expression), and entity framework cannot (will not) just call it to obtain value. It will try to translate it to SQL query, but has no idea what to do with GetAll method.
I assume you are trying to do a left join.
Your query:
var query = from customer in Customers
join broker in InsuredBrokers
on customer.InsertId equals broker.InsertId
into resutGroups
select new { Name = broker.Name, InsertId= broker.InsertId};
If you need entries for no maches use DefaultIfEmpty.
You can refer to this for more on the same.

LINQ to Entities does not recognize the method Generic.List(int) to Generic.IEnumerable(int) method

The database contains Orders.
Orders can be contained within a group of Orders.
For every group of Orders it could contain 1 to many Orders.
However, Orders could have a NULL value assigned GroupOrderId as previous Orders did not have the grouping concept. Only new Orders enforce the concept of being added to a group.
The class structure to be populated in order to perform actions on each Order is
public class OrdersGroup
{
public int? GroupOrderId { get; set; }
public List<int> OrderIds { get; set; }
}
The linq statement
var workPacketOrdersList = (from o in db.Orders
where
o.GroupOrderId >= groupOrderIdMin && o.GroupOrderId <= groupOrderIdMax &&
o.IsDeleted == false
orderby o.WorkPacketId ascending
group o by o.WorkPacketId
into grp
select new OrdersGroup
{
GroupOrderId = grp.Key,
OrderIds = grp.Select(g => g.OrderId).ToList()
}).ToList();
Full exception
LINQ to Entities does not recognize the method 'System.Collections.Generic.List`1[System.Int32] ToList[Int32](System.Collections.Generic.IEnumerable`1[System.Int32])' method, and this method cannot be translated into a store expression.
I see that the returned type of the linq query is a List<OrdersGroup>.
If the final .ToList() is omitted from the query than the return type becomes an IQueryable<OrdersGroup>
No matter what action is performed next the result is an exception that this method cannot be translated into a store expression.
I have tried to remove the specific select new OrdersGroup into a more generic select new and then perform actions on this result only to find the same store expression exception.
Can someone give some insight into where this linq is incorrect?
this is the part that's failing - grp.Select(g => g.OrderId).ToList() - you can't have a .ToList() in the select clause. remove that and you should be fine.
The problem is that LINQ to Entities is attempting to convert your query into SQL. It doesn't know how translate ToList into SQL, so that's the problem. You need to remove the call to ToList from inside your query.
That is,
OrderIds = grp.Select(g => g.OrderId).ToList()
LINQ to Entities can not convert that to SQL. Remove the call
OrderIds = grp.Select(g => g.OrderId)
and if you need OrderIds to be a List<int>, do the call to ToList after you execute the query.
It's because you're trying to call ToList() in a part of the query that will become raw SQL and executed at the source (ie SQL Server, not the CLR). I don't know exactly what your data is so I can't necessarily make an accurate recommendation on how to fix it but I would try taking making the ToList() call after this query or just not making it all. It's likely IEnumberable will offer whatever functionality you need which is what the Select will return if you remove the ToList() call.
By the way since I wasn't explicit, I'm referring to the ToList() call inside the select -(second to last line) OrderIds = grp.Select(g => g.OrderId).ToList() the other one is fine. It's executed on the results of the SQL query which is perfectly fine, you just can't make calls to C# specific methods within a query that will be executed by the SQL provider.
Your problem is that you select a list in your select statement.
select new OrdersGroup
{
GroupOrderId = grp.Key,
OrderIds = grp.Select(g => g.OrderId).ToList()
/////////////////////////////////////^^^^^^^^^HERE
}
What you need to do is change OrderIds to an IEnumerable<int>, and then get rid of the ToList.

LINQ 'AsEnumerable' and the Entity Framework

I am writing a LINQ query similar to the following:
var test = from o in dbcontext.Orders.AsEnumerable()
where o.ID==1
select new Order
{
Name = GetName(o.ID)
};
In order to call an external function within the LINQ query, I am using AsEnumerable() within the query.
I understand that normally the query is not executed until an enumeration function like ToList(), etc. is called. But here I am calling the enumeration within the query.
Can anyone tell me if it is considered bad practice to use AsEnumerable() like this? Will it suffer in performance compared to calling ToList() after creating the query?
I'd do
var ids = from o in dbcontext.Orders
where o.ID==1
select new { ID = o.ID };
var names = from i in ids.AsEnumerable()
select new Order { Name = GetName(i.ID) };
i.e. do as much querying as possible in the database, and then only perform the ID-to-name transformation in C#.

EF using LINQ trying Contains In passing in a Array

Is there a better way to write this CONTAINS from an ARRAY?
I am passing a string/array into my LINQ statement. In SQL the code that is working is
SELECT * FROM dbo.option1
WHERE option1Code IN ('9841','V237','SV02','2057')
In EF using LINQ I am trying
using (var ctx = new ProductEntities())
{
//--------------------------------------------------------------------//
string csvSKU = '984,237,102,207';
string[] mArray = csvSKU.Split(',');
var results = (from o in ctx.option1
join p in ctx.Products on o.option1Code equals p.productSKU
where mArray.Contains(o.option1Code)
orderby o.option1Sort
select o).Distinct().ToList();
return results;
}
This looks perfectly fine and should result in similar SQL as you posted (at least for the Contains part).
Also not really sure what your join is for right now - are there any option codes that have no entry in the Products table / productSKU?

How can I implement the following SQL query as linq to entities query?

How can I implement the following SQL query as linq to entities query?
select *, MIN(QueuedDate)
from pcm_transactions
where QueuedDate IS NOT NULL And ExecutionDate IS NULL
group by SimId
I spent hours thinking and trying varius methods - hope to find the right answer here.
EDIT:
Here is one of my first tries:
// Get the oldest queued action
var queuedTransactions =
(from t in db.TransactionSet
where t.QueuedDate.HasValue && !t.ExecutionDate.HasValue
group t by new { t.TransactionId, t.QueuedDate } into tr
select new
{
Transaction = db.TransactionSet.First(q => q.TransactionId == tr.Key.TransactionId),
QueuedDate = tr.Min(m => m.QueuedDate)
}).ToList();
One problem is that the SQL isn't valid to start with; You have to
group by every column that is not an aggregate expression (eg. min/max
etc), so "select *" simply doesn't make sense. Do you have sample data
and required results to help us rewrite this into Linq?
– Quoted from Will's comment

Categories

Resources