Why I'm still getting System.NotSupportedException - c#

My code is:
using( var ctxA = new AEntities())
using( var ctxB = new BEntities())
{
var listOfA = (from A in AEntities.AEntity select A).ToList();
var listOfB = (from B in BEntities.BEntity
where listOfA.Select( A = A.Id)contains(B.Id)
select B).ToList();
}
I'm getting the error:
The specified LINQ expression contains references to queries that are associated with different contexts.
However, because of 'ToList' I already did a fetch in AEntity thats makes second query only about one of the contexts, did not?
How can a separate the two queries still using one list to query the other?

Try to store just IDs into listOfA
var listOfA = (from A in AEntities.AEntity select A.Id).ToList();
var listOfB = (from B in BEntities.BEntity
where listOfA.Contains(B.Id)
select B).ToList();

If anyone wants to know, the answer to my question was:
var listOfA = (from A in AEntities.AEntity select A.Id).ToList();
List<long> listOfIdsOfA = listOfA.Select( A=>A.id).ToList();
var listOfB = (from B in BEntities.BEntity
where listOfIdsOfA.Contains(B.Id)
select B).ToList();
The only difference to Selman's answer was the creation of Id's list after the first query. That's why I need the whole entity too.

Related

Linq Join to List

I have a list as follows:
List<int> loc = new List<int>();
which I populate.
Note that the list stores int values.
I like to join this list to a db table as follow.
What I need to do is something like:
var result = (from pc in db.loc_details
join l in loc
on pc.locid = loc
select pc).ToList();
I get an error obviously: Cannot implicitly convert type 'System.Connection.Generics.List to 'int'.
What is the best approach to do this?
You're trying to join a single int to the entire list.
Try
var result = (from pc in db.loc_details
join l in loc
on pc.locid equals l
select pc).ToList();
although that will gve you a different error if you are using EF since it can't translate a join to an in-memory list to SQL. If that is the case, you can use Contains which gets translated to an IN clause:
var result = (from pc in db.loc_details
where loc.Contains(pc.locid)
select pc).ToList();
You wrote:
List<int> loc = new List<int>();
var result = (from pc in db.loc_details
join l in loc
on pc.locid = loc
select pc);
Answer yourself: what is the type of pc.LocId? And what is the type of loc?
Now look at your code:
on pc.locid = loc
by the way, shouldn't the = be equals or at least ==?

Data in Linq query not in join is not in output to json only those that are related in 2 classes are showing up

The basis of this question is from this question:
Combine 2 classes with adding data and 1 table has a colllection list of the other table and wanting to use linq to display
In which I "thought" the problem was solved.
However as I added in a new object to the List, now this join query does not output it
reportData.Add(new ReportData() {ReportGroupId = 3, ReportGroupName = "Straggler", SortOrder = 3, Type = 1});
var reports = reportDefinition.GroupBy(r=>r.ReportGroupId);
var query = reportData.Join(reports, d => d.ReportGroupId, gr => gr.Key,
(r,gr) => new
{
r.ReportGroupName,
items = gr.ToList(),
r.ReportGroupId
});
Here is the dotNetFiddle https://dotnetfiddle.net/IIBFKG
Why doesn't the item that I added to the ReportData not show up? Is it the type of JOIN in Linq?
I think the linked question was not answered correctly.
Looks like all you need is a simple Group Join:
var query =
from d in reportData
join r in reportDefinition on d.ReportGroupId equals r.ReportGroupId into items
select new
{
d.ReportGroupName,
items = items.ToList(),
d.ReportGroupId
};

Unioning two LINQ queries

I just need to make full outer join with Linq, But When i union two quires i get this error:
Instance argument: cannot convert from 'System.Linq.IQueryable' to 'System.Linq.ParallelQuery
And here is my full Code:
using (GoodDataBaseEntities con = new GoodDataBaseEntities())
{
var LeftOuterJoin = from MyCustomer in con.Customer
join MyAddress in con.Address
on MyCustomer.CustomerId equals MyAddress.CustomerID into gr
from g in gr.DefaultIfEmpty()
select new { MyCustomer.CustomerId, MyCustomer.Name, g.Address1 };
var RightOuterJoin = from MyAddress in con.Address
join MyCustomer in con.Customer
on MyAddress.CustomerID equals MyCustomer.CustomerId into gr
from g in gr.DefaultIfEmpty()
select new { MyAddress.Address1, g.Name };
var FullOuterJoin = LeftOuterJoin.Union(RightOuterJoin);
IEnumerable myList = FullOuterJoin.ToList();
GridView1.DataSource = myList;
GridView1.DataBind();
}
The types of your two sequences are not the same, so you can't do a Union.
new { MyCustomer.CustomerId, MyCustomer.Name, g.Address1 };
new { MyAddress.Address1, g.Name };
Try making sure that the fields have the same names and types in the same order.
Why not select it all as one thing? Depending on your setup (i.e., if you have foreign keys properly set up on your tables), you shouldn't need to do explicit joins:
var fullJoin = from MyCustomer in con.Customer
select new {
MyCustomer.CustomerId,
MyCustomer.Name,
MyCustomer.Address.Address1,
MyCustomer.Address.Name
};
Method syntax:
var fullJoin = con.Customers.Select(x => new
{
x.CustomerId,
x.Name,
x.Address.Address1,
x.Address.Name
});
union appends items from one collection to the end of another collection, so if each collection had 5 items, the new collection will have 10 items.
What you seem to want is to end up with 5 rows with more infomration is each. That's not a job for Union. You might be able to do it with Zip(), but you'll really be best with the single query as shown by DLeh.

LINQ using dictionary in where clause

er have the following query in linq...
Whenever I try to run it I get a No comparison operator for type System.Int[] exception.
It's got something to do with the dictionary I am sure, but I don't understand why this isn't valid and was wondering if someone could explain?
// As requested... not sure it will help though.
var per = (
from p in OtherContext.tblPeriod
where activeContractList.Select(c => c.DomainSetExtensionCode).Contains(p.DomainSetExtensionCode)
select p).ToArray();
var com = (
from c in MyContext.tblService
join sce in MyContext.tblServiceExtension
on c.ServiceExtensionCode equals sce.ServiceExtensionCode
join sc in MyContext.tblServiceContract
on sce.ServiceContractCode equals sc.ContractCode
group sc by c.Period into comG
select new
{
PeriodNumber = comG.Key,
Group = comG,
}).ToArray();
var code =
(from c in com
join p in per on c.PeriodNumber equals p.PeriodNumber
select new
{
p.Code,
c.Group
}).ToArray();
var payDictionary = new Dictionary<int, int[]>();
// This is another linq query that returns an anonymous type with
// two properties, and int and an array.
code.ForEach(c => payDictionary.Add(c.Code, c.Group.Select(g => g.Code).ToArray()));
// MyContext is a LINQ to SQL DataContext
var stuff = (
from
p in MyContext.tblPaySomething
join cae in MyContext.tblSomethingElse
on p.PaymentCode equals cae.PaymentCode
join ca in MyContext.tblAnotherThing
on cae.SomeCode equals ca.SomeCode
where
// ca.ContractCode.Value in an int?, that should always have a value.
payDictionary[p.Code].Contains(ca.ContractCode.Value)
select new
{
p.Code,
p.ExtensionCode,
p.IsFlagged,
p.Narrative,
p.PayCode,
ca.BookCode,
cae.Status
}).ToList();
You won't be able to do this with a dictionary. The alternative is to join the three linq queries into one. You can do this with minimal impact to your code by not materializing the queries with ToArray. This will leave com and code as IQueryable<T> and allow for you compose other queries with them.
You will also need to use a group rather than constructing a dictionary. Something like this should work:
var per = (
from p in OtherContext.tblPeriod
where activeContractList.Select(c => c.DomainSetExtensionCode).Contains(p.DomainSetExtensionCode)
select p.PeriodNumber).ToArray(); // Leave this ToArray because it's materialized from OtherContext
var com =
from c in MyContext.tblService
join sce in MyContext.tblServiceExtension on c.ServiceExtensionCode equals sce.ServiceExtensionCode
join sc in MyContext.tblServiceContract on sce.ServiceContractCode equals sc.ContractCode
group sc by c.Period into comG
select new
{
PeriodNumber = comG.Key,
Group = comG,
}; // no ToArray
var code =
from c in com
where per.Contains(c.PeriodNumber) // have to change this line because per comes from OtherContext
select new
{
Code = c.PeriodNumber,
c.Group
}; // no ToArray
var results =
(from p in MyContext.tblPaySomething
join cae in MyContext.tblSomethingElse on p.PaymentCode equals cae.PaymentCode
join ca in MyContext.tblAnothThing on cae.SomeCode equals ca.SomeCode
join cg in MyContext.Codes.GroupBy(c => c.Code, c => c.Code) on cg.Key equals p.Code
where cg.Contains(ca.ContractCode.Value)
select new
{
p.ContractPeriodCode,
p.DomainSetExtensionCode,
p.IsFlagged,
p.Narrative,
p.PaymentCode,
ca.BookingCode,
cae.Status
})
.ToList();
Side Note: I also suggest using navigation properties where possible instead of joins. It makes it much easier to read and understand how objects are related and create complex queries.

Creating a LINQ select from multiple tables

This query works great:
var pageObject = (from op in db.ObjectPermissions
join pg in db.Pages on op.ObjectPermissionName equals page.PageName
where pg.PageID == page.PageID
select op)
.SingleOrDefault();
I get a new type with my 'op' fields. Now I want to retrieve my 'pg' fields as well, but
select op, pg).SingleOrDefault();
doesn't work.
How can I select everything from both tables so that they appear in my new pageObject type?
You can use anonymous types for this, i.e.:
var pageObject = (from op in db.ObjectPermissions
join pg in db.Pages on op.ObjectPermissionName equals page.PageName
where pg.PageID == page.PageID
select new { pg, op }).SingleOrDefault();
This will make pageObject into an IEnumerable of an anonymous type so AFAIK you won't be able to pass it around to other methods, however if you're simply obtaining data to play with in the method you're currently in it's perfectly fine. You can also name properties in your anonymous type, i.e.:-
var pageObject = (from op in db.ObjectPermissions
join pg in db.Pages on op.ObjectPermissionName equals page.PageName
where pg.PageID == page.PageID
select new
{
PermissionName = pg,
ObjectPermission = op
}).SingleOrDefault();
This will enable you to say:-
if (pageObject.PermissionName.FooBar == "golden goose") Application.Exit();
For example :-)
If you don't want to use anonymous types b/c let's say you're passing the object to another method, you can use the LoadWith load option to load associated data. It requires that your tables are associated either through foreign keys or in your Linq-to-SQL dbml model.
db.DeferredLoadingEnabled = false;
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<ObjectPermissions>(op => op.Pages)
db.LoadOptions = dlo;
var pageObject = from op in db.ObjectPermissions
select op;
// no join needed
Then you can call
pageObject.Pages.PageID
Depending on what your data looks like, you'd probably want to do this the other way around,
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Pages>(p => p.ObjectPermissions)
db.LoadOptions = dlo;
var pageObject = from p in db.Pages
select p;
// no join needed
var objectPermissionName = pageObject.ObjectPermissions.ObjectPermissionName;
You must create a new anonymous type:
select new { op, pg }
Refer to the official guide.
If the anonymous type causes trouble for you, you can create a simple data class:
public class PermissionsAndPages
{
public ObjectPermissions Permissions {get;set}
public Pages Pages {get;set}
}
and then in your query:
select new PermissionsAndPages { Permissions = op, Page = pg };
Then you can pass this around:
return queryResult.SingleOrDefault(); // as PermissionsAndPages
change
select op)
to
select new { op, pg })

Categories