Unable to cast anonymous list into known list in LINQ - c#

I have a LINQ Query which returns me results from one table. I need to convert it into the List of that table model. The anonymous type of groupManager is List<a> wherea is {Group g5}
var groups = new List<Group>();
var groupManager = (from a in db.AUsers
join b in db.BUsers on a.Id equals b.UserID into group1
from g1 in group1.DefaultIfEmpty()
join c in db.UserRoles on g1.ID equals c.UserID into group2
from g2 in group2.DefaultIfEmpty()
join d in db.Roles on g2.RoleID equals d.ID into group3
from g3 in group3.DefaultIfEmpty()
join e in db.RoleGroups on g3.ID equals e.RoleID into group4
from g4 in group4.DefaultIfEmpty()
join f in db.Groups on g4.GroupID equals f.ID into group5
from g5 in group5.DefaultIfEmpty()
where a.Id == user.ID && g5.Name != ""
select new{ Group = g5}).ToList();
groups = groupManager.Cast<Group>().ToList();
This code does not seem to work.The error I am getting is {"Unable to cast object of type '<>f__AnonymousType11`1[Group]' to type 'Group'."} Am I missing something?

hmmm... did you try this?
select new Group(g5)).ToList();
or this
select g5).ToList();
hard to say more without knowing anything about the group object or the other types in your example.

You can likely do this without the anonymous type or the cast.
var groups = (from a in db.AUsers
// Your query...
select new Group
{
// Properties of Group
Name = g5.Name,
AnotherProperty = g5.AnotherProperty
}).ToList();

Provided answers were absolutely correct, but I guess it could be good to point one subtle thing out regarding Cast method (and to answer "Am I missing something" part).
Cast method really serves different purpose than casting all objects in list to another type. No surprise that compiler throws this exception since what Cast does is taking IEnumerable (non generic version) and returning the same collection, but with generic IEnumerable<T>. This is one of two methods in LINQ that are taking non generic IEnumerable as an argument (the second is OfType), so you could have a collection of given type, cast it to IEnumerable<T> and use other LINQ methods which require IEnumerable<T> as an argument.
Just look at the source code
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) {
IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
if (typedSource != null) return typedSource;
if (source == null) throw Error.ArgumentNull("source");
return CastIterator<TResult>(source);
}
and in CastIterator
foreach (object obj in source) yield return (TResult)obj;
so your collection should be able to be casted to given type T in order to Cast to work. It won't cast your anonymous types to concrete types.

If you select the actual object then that's what you get back as an IEnumerable of Group:
var groups = new List<Group>();
var groupManager = (from a in db.AUsers
join b in db.BUsers on a.Id equals b.UserID into group1
from g1 in group1.DefaultIfEmpty()
join c in db.UserRoles on g1.ID equals c.UserID into group2
from g2 in group2.DefaultIfEmpty()
join d in db.Roles on g2.RoleID equals d.ID into group3
from g3 in group3.DefaultIfEmpty()
join e in db.RoleGroups on g3.ID equals e.RoleID into group4
from g4 in group4.DefaultIfEmpty()
join f in db.Groups on g4.GroupID equals f.ID into group5
from g5 in group5.DefaultIfEmpty()
where a.Id == user.ID && g5.Name != ""
select g5).ToList()
groups = groupManager;
The .ToList() will then convert it to a list. No need to create a dynamic object and then cast.

Related

What determines what the Where in a Linq statement is able to parse?

In the Where clause of a Linq statement, like this,
var myClasses = (from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
where (b.Active == 1)
select new { b });
The expression b.Active==1 works fine. But if I do this,
Expression<Func<MyRecords, bool>> filter = my => my.Active == 1;
[Update: Because of Hans' answer I have kept this as the original, but in reality, I mistyped here. The Expression is actually using the underlying type, not the EF generated plural like the query Linq. I actually have this,
Expression<Func<MyRecord, bool>> filter = my => my.Active == 1;
]
And try this,
var myClasses = (from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
where (filter)
select new { b });
The compiler complains,
Cannot convert query expression to intended delegate type because some
of the return types in the block are not implicitly convertible to the
delegate return type
I have seen lots of SO question with this, but I do not understand why it will not work. I am misunderstanding fundamental, so I'm not really asking anyone to write the code. I want to know what Linq wants so I have a better understanding of Linq, not just making something work. This works, for example,
var myClasses = (from b in db.MyRecords.Where(filter)
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
select new { b });
I want to know why it works there and not in the Where after the joins. If I do the Where at the end of the joins, the compiler is still aware of the MyRecords fields, including Active.
I think this is what I'm after for a proper description, as it seems to fit my probably pretty well.
http://www.albahari.com/nutshell/linqkit.aspx
Your filter is just of wrong type to be applied in the first example. The blue linq syntax does a lot of magic for you to make this query easy to read. What actually happens under the hood is creation of some anonymous types that contain references to your items. Note that in that where clause you can use p and cse variables as well. And when you factor that to your expression you might figure it to be like this Expression<Func<Tuple<MyRecords, People, Courses>> in reality it will not be a tuple but some anonymous type.
When you ask resharper to convert blue syntax to method chain it generates it like this:
(db.MyRecords.Join(
db.People,
b => b.PersonId,
p => p.PersonId,
(b, p) => new {b, p})
.Join(
db.Courses,
t => t.b.CourseId,
cse => cse.CourseId,
(t, cse) => new {t, cse})
.Where(t => (t.t.b.Active == 1))
.Select(t => new {t.t.b}));
And actually you cannot use the filter variable in the blue syntax like you did:
... join cse in db.Courses on b.CourseId equals cse.CourseId
where (filter)
You would have to switch to method call:
(from b in db.MyRecords
join p in db.People on b.PersonId equals p.PersonId
join cse in db.Courses on b.CourseId equals cse.CourseId
select b)
.Where(filter)
now just because we trimmed the inner query to just b you can apply you filter.

How to join 2 tables using linq but avoid anonymous object

I want to join 2 tables using linq and avoid anonymous object.
So far i use tuple.
var products = from tm in db.TargetMarkets
join tp in db.Products on tm.product_id equals tp.id
where tm.country == 2
select Tuple.Create<TargetMarket, Product>(tm, tp);
But, when i foreach
foreach (var p in products)
{
var a = p.Item1.id;
}
It throws an exception
LINQ to Entities does not recognize the method 'System.Tuple`2
Question:
Is there a way to keep my code strongly typed
What's wrong with tuple (optional)
Is there a way to keep my code strong type
You can define a new type and make object of that type instead of anonymous object.
class ProductTargetMarket
{
//Attributes
}
var ProductsTargetMarkets = from tm in db.TargetMarkets
join tp in db.Products on tm.product_id equals tp.id
where tm.country == 2
select new ProductTargetMarket{Attribute1OfProductTargetMarket = tp.Attribute1, Attribute1OfProductTargetMarket = tm.Attribute1 };
To create a tuple you may first convert it to anonymous type and then convert it to tuple, see this this and this post.

LINQ 'query syntax' -- where clause filtering against List of int

Struggling on how to get this filter to work:
var categoryIDs = new List<int>();
categoryIDs.Add(2);
categoryIDs.Add(3);
var dbContacts = (from cnt in _db.Contacts
join ucc in _db.UserContactCategories on cnt.id equals ucc.ContactID
join cat in _db.Categories on ucc.CatDescID equals cat.id
where categoryIDs.Equals(cnt.id)
select new {cnt.id,
cnt.GivenName,
cnt.SurName
}).ToList();
Getting this error message:
Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types
You are are trying to compare a List<int> to an int, which won't work.
If you're looking to get all contacts that are in your hard coded List<int>, just use the Contains method.
var categoryIDs = new List<int>();
categoryIDs.Add(2);
categoryIDs.Add(3);
var dbContacts = (from cnt in _db.Contacts
join ucc in _db.UserContactCategories on cnt.id equals ucc.ContactID
join cat in _db.Categories on ucc.CatDescID equals cat.id
where categoryIDs.Contains(cat.id)
select new {cnt.id,
cnt.GivenName,
cnt.SurName
}).ToList();

Find missing items in a List<T>

Can someone convert this to C# LINQ for me please ??
SELECT *
FROM vf
LEFT JOIN dbvf
ON vf.sid =dbvf.sid
AND vf.cid =dbvf.cid
WHERE dbvf.sid IS NULL
Both vf and dbvf are List<T>. sid and cid are integers.
What I am trying to do is find items in vf that are missing in dbvf.
try this
var ret = from p1 in vf
join p2 in dbvf
on p1.sid equals p2.sid && p1.cid equals p2.cid into g
from p2 in g.DefaultIfEmpty()
where p2 == null
select new {vf=p1, dbvf=p2}
or this simple
vf.Except(dbvf);
something like below
from dbvf in dbvfs
from vf in vfs
where vf.sid == dbvf.sid && vf.cid == dbvf.cid
where dbvf.sid == null
select new { dbvf = dbvf, vf = vf}
Try something like this:
var query =
from v in vf
join d in dbvf
on new { v.sid, v.cid }
equals new { d.sid, d.cid } into gj
where !gj.Any()
select v;
As stated earlier, your purpose is to do an "except". I've answered how to do this with left-join semantics.
var query =
from v in vf
join d in dbvf
on new { v.sid, v.cid }
equals new { d.sid, d.cid } into gj
from d in gj.DefaultIfEmpty()
where d == null
select v;
The anonymous types used here appear to be black magic to the uninitiated. However, the compiler creates the anonymous types (actually it's just one type) with exactly two properties named sid and cid as well as providing implementations for Equals and GetHashCode that Join will use in its implementation. My choice of gj for the into clause is because introducing the into causes the compiler to do a GroupJoin instead of a regular Join call.
I can add to the query to get a similar feel to your SQL sample by adding a from d in gj.DefaultIfEmpty() clause that reinstates the d range variable previously hidden by the into clause. Now I can add the where d == null clause nearly reaching parity with the original SQL.
This anonymous type introduction is something you may need to use again if you ever want to do other operations such as group by both sid and cid.

Compose an entity object from a 'join' query

I have this Linq query, that I tried to simplify :
List<A> LR = (from a in ent.A
join b in ent.B on a.ID equals b.idarticle
join c in ent.C on b.idB equals c.id
select new A()
{ name=a.name, surname = c.surname
}).toList();
in a few words I need a field of A taken from table C (via a cross table B), so that 'name' from A and 'surname' from C compose a new A.
But I get "Cannot build entity type A"... while it's ok for an anonymous type...is it possible to get it ? I know I would need a new class type and populate it, but this is shorter.
thanks,
Saverio
That error has to do possibly with of restrictions in entity framework. So you could let ef return anonymous object, and then transform it into List<A>
List<A> LR = (from a in ent.A
join b in ent.B on a.ID equals b.idarticle
join c in ent.C on b.idB equals c.id
select new
{ name=a.name, surname = c.surname
})toList().Select(anon => new A() { name=anon.name, surname = anon.surname });

Categories

Resources