Stack overflow in LINQ to SQL and the Contains keyword - linq

I have an Extension method which is supposed to filter a Queryable object (IQueryable) based upon a collection of Ids....
Note that IQueryable is sourced from my database via a LinqToSql request
public static IQueryable<NewsItemSummary> WithID(this IQueryable<NewsItemSummary> qry, IQueryable<Guid> Ids)
{
return from newsItemSummary in qry
where Ids.Contains(newsItemSummary.ID)
select newsItemSummary;
}
If Ids are created from an array or list and passed in as a queryable list, it DOESNT work
For example...
GetNewsItemSummary().WithID(ids.AsQueryable<Guid>())
If Ids is composed form a LinqToSql request, it DOES work!!
This is known issue:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=355026
My Ids collection cannot come from a LinqToSql request...
Note, if I change the function so that it consumes and IList rather than an IQueryable....
public static IQueryable<NewsItemSummary> WithID(this IQueryable<NewsItemSummary> qry, IList<Guid> Ids)
{
return from newsItemSummary in qry
where Ids.Contains(newsItemSummary.ID)
select newsItemSummary;
}
I now get the following exception:
Method 'Boolean Contains(System.Guid)' has no supported translation to SQL.
So... all I want to do is filter my collection of news based upon a list or array of Guids.... Ideas???

This will translate.
public static IQueryable<NewsItemSummary> WithID(
this IQueryable<NewsItemSummary> qry,
List<Guid> Ids
)
{
return from newsItemSummary in qry
where Ids.Contains(newsItemSummary.ID)
select newsItemSummary;
}
)
Translation of the Contains method against local collections was one of the last features added in the development of linq to sql for .net 3.5, so there are some cases that you would expect work that don't - such as translation of IList<T>.
Also, be aware that while LinqToSql will happily translate lists containing a vast number of items (I've seen it do over 50,000 elements), SQL Server will only accept 2,100 parameters for a single query.

Related

How can I delete all records from a table?

I've been searching for an answer on how to delete ALL records from a table using LINQ method syntax but all answers do it based on an attribute.
I want to delete every single record from the databse.
The table looks like so:
public class Inventory
{
public int InventoryId { get; set; }
public string InventoryName { get; set; }
}
I'm not looking to delete records based on a specific name or id.
I want to delete ALL recods.
LINQ method syntax isn't a must, bt I do prefer it since it's easier to read.
To delete all data from DB table I recommend to use SQL:
Trancate Table <tableName>
Linq is not meant to change the source. There are no LINQ methods to delete or update any element from your input.
The only method to change you input, is to select the (identifiers of the )data that you want to delete in some collection, and then delete the items one by one in a foreach. It might be that your interface with the source collection already has a DeleteRange, in that case you don't have to do the foreach.
Alas you didn't mention what your table was: Is it a System.Data.DataTable? Or maybe an Entity Framework DbSet<...>? Any other commonly used class that represents a Table?
If you table class is a System.Data.DataTable, or implements ICollection, it should have a method Clear.
If your tabls is an entity framework DbSet<...>, then it depends on your Provider (the database management system that you use) whether you can use `Clear'. Usually you need to do the following:
using (var dbContext = new MyDbContext(...))
{
List<...> itemsToDelete = dbContext.MyTable.Where(...).ToList();
dbContext.MyTable.RemoveRange(itemsToDelete);
dbContext.SaveChanges();
}

Implementing service queryables: IQueryable to IEnumerable and back

In RIA Services (and probably other frameworks such as WCF Data Services) one can implement data services methods by supplying methods returning an IQuerably. For example:
IQueryable<Customer> GetCustomers()
{
return this.DbContext.Customers.Where(c => !c.IsDeleted);
}
A query from the client can then supply an additional filter (among other things). Both the client-provided filter and the filter for returning only undeleted customers will be combined an sent to the database in SQL by entity framework (or whatever ORM is used).
Often entity framework isn't powerful enough to express the query one wants to write, in which case we have to go to linq to objects:
IQueryable<CustomerWithFluff> GetCustomers()
{
var customers =
this.DbContext.Customers
.Include("FluffBits")
.Where(c => !c.IsDeleted)
.ToList();
return
from c in customers
select new CustomerWithFluff()
{
CustomerName = c.Name,
ComplexFluff = String.Join(", ", from b in c.FluffBits select b.FluffText)
};
}
The sql to the database will now still contain the restriction on "IsDeleted", but not any further filter provided by a client: Those will be applied on the linq to objects level after all the data has already been fetched.
If I don't care to let the client filter on any of the data that I need to compose with linq-to-objects (only "ComplexFluff" in this example), is there a way to still allow filtering on the properties that are simply projected (only "CustomerName" in this example)?
Yes there is, however is not as simple as one can expect. You have to override the
public override IEnumerable Query(QueryDescription queryDescription, out IEnumerable<ValidationResult> validationErrors, out int totalCount)
method, where you can get, in queryDescription.Query the actual query and Expression that is going to be executed against your Queryable (that is, what is being returned by queryDescription.Method.Invoke(this, queryDescription.ParamterValues)).
You can then get the expression sent by the client and pass it to your method (maybe as a reference to some sort of field in you domainService, don't forget that WCF Ria Services are instantianted at each call, i.e. like a regular wcf perCall instancing model) where you'll have to combine
var customers =
this.DbContext.Customers
.Include("FluffBits")
.Where(c => !c.IsDeleted)
prior to the "ToList()" method call.
Not easy, but quite possible

How can I create a LINQ view?

My team is using Entity Framework 4.3.0 - Code Only with POCO classes as our ORM. Right now we use DBSets of Classes to access our 'tables'
Public Property Customers As DbSet(Of Customers)
But often we are doing soft deletes based on a IsDeleted column in LINQ, and filtering our select statements accordingly:
Dim LiveCustomers =
From C In EM.Customers
Where C.DeleteFlag = False
What I would really like to do is, instead of writing every query to include this filter, create some lower level property (possibly at our inherited DbContext level) that provides the filtered set, while maintaining strong type.
I tried this:
Public Property Customers As DbSet(Of Customer)
Public Property Customers_Live As DbSet(Of Customer)
Get
Return From C In Customers
Where C.DeleteFlag = False
End Get
Set(value As DbSet(Of Customer))
Customers = value
End Set
End Property
However that yielded me this error:
Multiple object sets per type are not supported. The object sets 'Customers' and 'Customers_Live' can both contain instances of type '__.Customer'.
A quick check on google yielded this promising result (How to: Query Objects with Multiple Entity Sets per Type) But after updating my Connection String, I'm still getting the same error.
<add name="EntityManager"
providerName="System.Data.SqlClient"
connectionString="
Data Source=xxxxxx;
Initial Catalog=xxxxxx;
User Id=xxxxxx;
Password=xxxxxx;
MultipleActiveResultSets=True"/>
So my question is, how could I effectively create a LINQ view that allows me to apply filtering, without impacting the upstream usage too drastically?
Change your property like this:
Public Property Customers As DbSet(Of Customer)
Public Property Customers_Live As IQueryable(Of Customer)
Get
Return From C In Customers
Where C.DeleteFlag = False
End Get
End Property
This is slightly different, as you won't have things like Add() or Remove(), but for a view you typically wouldn't expect to have that kind of functionality. If you want to add a new one, or remove one you should use the normal Customers property.
You could have your POCO classes inherit from a new class that has a new method that would do the filtering for you. Add something like this to the new class
--PSEUDO CODE!--
Public Function Filtered() as IEnumerable(Of Out T)
Return (From x In Me Where x.DeleteFlag).ToList()
End Function
and you could call it like:
Dim LiveCustomers =
From C In EM.Customers.Filtered
Or you could create an Interface and do a dependancy injection when you call your linq query. You'll have to google that one :)

Using IQueryable Or IEnumerable inside my search action method

i have the following action method:-
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Search(string q, int classid)
{
var users = r.searchusers(q, classid);
// code does here..............
which calls the following model repository method:-
public IQueryable<User> searchusers(string q, int id)
{
return from u in entities1.Users
where (!u.Users_Classes.Any(c => c.ClassID == id) && (u.UserID.Contains(q))
select u;
}
now if i change the IQueryable to IEnumerable as follow , will there be any changes on how the query will be executed in this case ?:-
public IEnumerable<User> searchusers(string q, int id)
{
return from u in entities1.Users
where (!u.Users_Classes.Any(c => c.ClassID == id) && (u.UserID.Contains(q))
select u;
}
Yes, in my testing once you cast to IEnumerable, that determines the query SQL. Any additional query composition you do after that will be done in memory after the query is executed.
So suppose you have a base query that loads a list of users and returns an IEnumerable. Then before you actually run through that list (thereby executing the query), you also add a .Where(i=>i.username='bob'). In that case, it will execute the whole select, and then apply a LINQ-to-Objects in memory filter for the "where username='bob'" part, which is probably not what you want, instead you want the whole thing to be run as part of the SQL statement.
So yes, always use IQueryable whenever you can so that your fully composed are run at once.
Yes it will change the query, you want to use the IQuerable for anything that uses a remote datasource.
In your case it will force linq to execute the query, where as IQuerable would wait until someone else to execute the query. IQuerable allows them, if they desire, to append more conditions to push down to the database for execution.
I generally enforce IEnumerable at the layer boundary, places where I dont want people modifying the queries that the system is going to generate.

Order By property from dynamic linq

I am using dynamic linq to make a generic class for processing a generic JqGrid from MVC all works fine (searching, pagination etc) except for sorting on code properties. Sorting works fine when I am hitting the DB to sort the data, but as soon as it is a property I have made the sorting does not work eg
public partial class tblStockOrder
{
public string approved
{
get
{
return approved_id == null ? "" : "Approved";
}
}
}
I am running the following Dynamic Linq
items = items
.OrderBy(string.Format("{0} {1}", sidx, sord))
.Skip(pageIndex * pageSize)
.Take(pageSize);
Where sidx etc are strings passed in by jquery.
So basically what is the best solution for handling a case where some properties will be from the db while others will be code properties (not sure of the correct naming). I can handle all this in code using reflection but would obviously like the DB to handle as much of the searching / sorting as possible without pulling in thousands of records and sorting through them in code using reflection.
Computed class will of course not work, as you're trying to create record which is part in memory, part in database.
You can, however, compute the same on database by specifying the function in linq query, example:
items = items
.OrderBy(x=> x.approved_id != null )
.Skip(pageIndex * pageSize)
.Take(pageSize);

Resources