Nested query using Linq with ToDictionary - linq

I'm having problems with this query using entity framework 4:
List<SomeResult> test = (from a in _entities.TableA
select new SomeResult
{
TestB = a.TableB.Name,
TestCDict = a.TableC.ToDictionary(x => x.SomeKey, x => x.SomeValue)
}).ToList();
It gives this error:
"Cannot compare elements of type 'System.Data.Objects.DataClasses.EntityCollection`1'. Only primitive types (such as Int32, String, and Guid) and entity types are supported."
How can I redo this query so it'll work? from a in _entities.TableA from c in a.TableC ....ToDictionary(.. ?
/Lasse

The problem is, that you are doing query against database. And LINQ provider that you are using, actually don't execute any of the operations, that you have written. It only tryes to translate all your code in Select into database query. Obviously, it can't parse really complex statents, like you have written with ToDictionary().
You can simply load all data from entities into memory, and then do all your dictionary stuff. Then your code will actually be executed, and should work.
Like:
List<SomeResult> test = from a in (from aa in _entities.TableA).AsEnumerable())
select new SomeResult
{
TestB = a.TableB.Name,
TestCDict = a.TableC.ToDictionary(x => x.SomeKey, x => x.SomeValue)
}).ToList();
Of course you can use DB side filtering in the inner query (before AsEnumerable()) to narrow amount of data loaded into memory.

Related

LINQ Select from dynamic tableName string

I want to get list of records from an entity model (I'm using EF version 5) with a particular accountID. I'm being supplied with the tableName string (this has to be dynamic) and the accountID. I'm trying the following 2 methods but none of them is working (giving me errors on the IQueryable object 'table':
PropertyInfo info = _db.GetType().GetProperty(tableName);
IQueryable table = info.GetValue(_db, null) as IQueryable;
var query = table.Where(t => t.AccountID == accID)
.Select(t => t);
List <object> recList = ( from records in table
where records.AccountID == accID
select records).ToList<object>();
The var query = table.Where(....).Select(...) is the correct move as it allows reflection for the query builder at runtime. However, t.AccountID is an error because of the type of t remains unknown.
I've previously used a similar approach in LINQ to SQL, using System.Linq.Expressions.Expression, e.g.:
// NOT TESTED
var table=context.GetTable(dynamicTableName);
var theT=table.Experssion; // actually, I forget. DynamicExpression or MemberBinding? or
var theField=Expression.Field(theT, "AccountID"); // or dynamic name
var query=table.Where(Expression.Equal(theField, accID);
var recList=query.ToList<object>();
If your object has a common interface there is a simpler syntax:
IQueryable<MyInterface> table = context.GetTable("table") as IQueryable<MyInterface>;
var recList=from r in table
where table.AccountID == ac // if your AccountID is on MyInterface
select table;
If you only have a few tables to support, you could do this as well:
IQueryable<MyInterface> table;
if("table1"==tableName)
table=_db.table1
elseif("table2"==tableName)
table=_db.table2
elseif("table3"==tableName)
table=_db.table3
else
throw exception
I built a DynamicRepository for a project I am working on. It uses generic methods exposed through EF along with dynamic linq. It might be helpful to look at that source code here:
https://dynamicmvc.codeplex.com/SourceControl/latest#DynamicMVC/DynamicMVC/Data/DynamicRepository.cs
You can query the entity framework metadata workspace to get the type for a given table name. This link might help:
Get Tables and Relationships

How to set Filter Values in LinQ with SQL Query Text?

I am using LINQ for my database application.
So I can write things like:
using (ShuttleDataContext dc = Config.GetNewShuttleDBConnection())
{
List<RefState> states = (from a in dc.RefStates select a).ToList();
return states;
}
Know I have to handle the requierement, that I have to filter from this database by SQL strings, e.g. a filter string: "ID like '7%'" or "Name = 'Red'".
Of course normaly I would write something like .Where(a => a.Name == "Red"), but it's nearly impossible to map every filterexpression to a where clause... So is there a method to have native T-SQL in an Linq-List?
As far as I know you can't just provide the filter condition, but you can use ExecuteQuery to execute an arbitrary SQL statement and map that to your LINQ types:
List<RefState> states = dc.ExecuteQuery<RefState>(
"SELECT * FROM RefStates WHERE ID LIKE '7%'").ToList();

Linq to Entities Query explanation

Is there any way I can make this Linq to entities query in another way (better) and understand what I did?
First, can I have the string.jon() in the first part (select(p => new {...)?
Second, why do I need the first select to end with .ToList() for the string.join() to work?
The tables relation are as follow:
And here is the code:
Productos.Select(p => new {
Id = p.Id,
Code = p.CodigoProd,
Name = p.Nombre,
Cant = p.Inventario.Sum(i => i.Cantidad),
Pric = p.Inventario.OrderBy(i => i.Precio).Select (i => i.Precio).FirstOrDefault(),
cate = p.ProductosXCategoria.Select(pc => pc.CategoriasdeProducto.Nombre)
}).Where (p => p.Cant != null).ToList()
.Select (r => new {
r.Id, r.Code, r.Cant, r.Name, r.Pric, Categ = string.Join("-",r.cate)
})
the result is this (which is the result i expected to be):
IEnumerable<> (17 items)
**Id-- Code-- Cant-- Name-- Pric-- Categ**
1-- AXI-- 30-- Pepsi-- 10-- Granos
3-- ASI-- 38-- Carne blanca-- 12-- Granos-Limpieza
The query looks fine to me.
The reason you can't move the string.Join method to the first Select, is that LINQ-to-Entities ultimately has to be able to translate to SQL. string.Join has no direct translation to SQL, so it doesn't know how to translate your LINQ query to it. By calling ToList() first, you bring the results of the first Select into memory, where the subsequent Select works with Linq-to-Objects. Since Linq-to-Objects does not need to translate to SQL, it can operate directly on the results of the first query in memory.
Generally, you would want to put everything that would be better left to SQL before the ToList() call (such as filtering, sorting, averaging, grouping, etc.), and leave additional work that can't be translated to SQL (or isn't as efficient to do so) for after the results have been brought into local memory.

Using .Contains within a linq query returning a SystemException

I am having some trouble with a linq query I am trying to write.
I have List A of products that have been modified so I am trying to get the list of products from the db to allow me to apply the changes to them.
I have tried 2 different queries
var query = from p in db.Products
where products.Select(z => z.id).Contains(p.Id)
select p;
var query2 = from p in db.Products where (from o in products
select o.id)
.Contains(p.Id)
select p;
Both attempts are returning an error
base {System.SystemException} = {"Unable to create a constant value of type 'ProjectABC.Models.ProductModel'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."}
What am I doing wrong?
I had the same problem the other day, seems EF doesn't support Select().Contains() without giving that error. After testing around for a bit, I ended up splitting it up in what in your case would correspond to;
var IDs = products.Select(z=>z.id);
var query = from p in db.Products
where IDs.Contains(p.Id)
select p;
which worked well in my case when the "products" collection was in memory anyway (ie a ToList()'ed result from the database)

Wait for DomainContext.Load<t> from an entityquery with joins to complete (returning new type via 'select new')

My app consolidates data from other DBs for reporting purposes. We can't link the databases, so all the data processing has to be done in code - this is fine as we want to allow manual validation during the imports.
Certain users will be able to start an update through the Silverlight 4 front end.
I have 3 tables in database x that are fed from one EF4 Model (ModelX). I want to join those tables together, select specific columns and return the result as a new entity that exists in a different EF4 Model (ModelY). I'm using this query:
var myQuery = from i in DBx.table1 from it in DBx.table2 from h in DBx.table3 where (i.id==it.id && h.otherid == i.otherid) select new ModelYServer {Name = i.name,Thing = it.thing, Stuff = h.stuff};
The bit i'm stuck on, is how to execute that query, and wait until the Asynchronous call has completed. Normally, i'd use:
DomainContext.Load<T>(myQuery).Completed += (sender,args) =>
{List<T> myList = ((LoadOperation<T>)sender.Entities.ToList();};
but I can't pass myQuery (an IEnumerable) into the DomainContext.Load() as that expects an EntityQuery. The dataset is very large, and is taking up to 30 seconds to return, so I definitely need to wait before continuing.
So can anyone tell me how I can wait for the IEnumerable query to complete, or suggest a better way of doing this (there very likely is one).
Thanks
Mick
One simple way is just to force it to evaluate by calling ToList:
var query = from i in DBx.table1
join it in DBx.table2 on i.id equals it.id
join h in DBx.table3 on i.otherid equals h.otherid
select new ModelYServer {
Name = i.name,
Thing = it.thing,
Stuff = h.stuff
};
// This will block until the results have been fetched
var results = query.ToList();
// Now use results...
(I've changed your where clause into joins on the earlier tables, as that's what you were effectively doing and this is more idiomatic, IMO.)

Resources