Linq Contains and Distinct - linq

I have the following 3 tables with their fields
Books(Id_Book | Title | Year)
Book_Themes (Id | Id_Book| Id_Theme)
Themes (Id_Theme| Title)
I also have an Giud array with Id_Themes
Guid [] themesArray = new Guid []{new Guid("6236c491-b4ae-4a2f-819e-06a38bf2cf41"), new Guid("06586887-7e3f-4f0a-bb17-40c86bfa76ce")};
I'm trying to get all Books containing any of the Theme_Ids from the themesArray
This is what I have so far which is not working. Not sure how to use Contains in this scnenario.
int index = 1; int size= 10;
var books = (from book in DB.Books
join bookWThemes in DB.Book_Themes
on book.Id_Book equals bookWThemes.Id_Book
where themesArray.Contains(bookWThemes.Id_Theme)
orderby book.Year
select book)
.Skip((index - 1) * page)
.Take(size);
I'm getting an error on themesArray.Contains(bookWThemes.Id_Theme): System.Guid[] does not contain a definition for Contains. Also I'm not sure where to put the Distinct
****UPDATE****
noticed that my Model had Id_Theme as nullable... I changed the DB and didn't reflect the changes on my model. So to answer the question if it's nullable just change the Contains line to themesArray.Contains(bookWThemes.Id_Theme.Value)... and with this change it works.
Thanks for all the help!.

It's strange that your LINQ query is breaking down on .Contains. All three of the forms IEnumerable<> and List<> work for me.
[Test]
public void Test43()
{
var a = new List<Guid>(){new Guid(),new Guid(),new Guid()};
a.Contains(new Guid()); // works okay
var b = (IEnumerable<Guid>)a;
b.Contains<Guid>(new Guid()); // works okay
b.Contains(new Guid()); // works okay
}

For the "distinct" question, put the call here:
select book)
.Distinct() // <--
.Skip((index - 1) * page)

Try casting the Guid[] to List<Guid> and then you can use Contains on it.
where themesArray.ToList().Contains(bookWThemes.Id_Theme)

Related

Dynamic Linq on DataTable error: no Field or Property in DataRow, c#

I have some errors using Linq on DataTable and I couldn't figure it out how to solve it. I have to admit that i am pretty new to Linq and I searched the forum and Internet and couldn't figure it out. hope you can help.
I have a DataTable called campaign with three columns: ID (int), Product (string), Channel (string). The DataTable is already filled with data. I am trying to select a subset of the campaign records which satisfied the conditions selected by the end user. For example, the user want to list only if the Product is either 'EWH' or 'HEC'. The selection criteria is dynaically determined by the end user.
I have the following C# code:
private void btnClick()
{
IEnumerable<DataRow> query =
from zz in campaign.AsEnumerable()
orderby zz.Field<string>("ID")
select zz;
string whereClause = "zz.Field<string>(\"Product\") in ('EWH','HEC')";
query = query.Where(whereClause);
DataTable sublist = query.CopyToDataTable<DataRow>();
}
But it gives me an error on line: query = query.Where(whereClause), saying
No property or field 'zz' exists in type 'DataRow'".
If I changed to:
string whereClause = "Product in ('EWH','HEC')"; it will say:
No property or field 'Product' exists in type 'DataRow'
Can anyone help me on how to solve this problem? I feel it could be a pretty simple syntax change, but I just don't know at this time.
First, this line has an error
orderby zz.Field<string>("ID")
because as you said, your ID column is of type int.
Second, you need to learn LINQ query syntax. Forget about strings, the same way you used from, orderby, select in the query, you can also use where and many other operators. Also you'll need to learn the equivalent LINQ constructs for SQL-ish things, like for instance IN (...) is mapped to Enumerable.Contains etc.
With all that being said, here is your query
var productFilter = new[] { "EWH", "HEC" };
var query =
from zz in campaign.AsEnumerable()
where productFilter.Contains(zz.Field<string>("Product"))
orderby zz.Field<int>("ID")
select zz;
Update As per your comment, if you want to make this dynamic, then you need to switch to lambda syntax. Multiple and criteria can be composed by chaining multiple Where clauses like this
List<string> productFilter = ...; // coming from outside
List<string> channelFilter = ...; // coming from outside
var query = campaign.AsEnumerable();
// Apply filters if needed
if (productFilter != null && productFilter.Count > 0)
query = query.Where(zz => productFilter.Contains(zz.Field<string>("Product")));
if (channelFilter != null && channelFilter.Count > 0)
query = query.Where(zz => channelFilter.Contains(zz.Field<string>("Channel")));
// Once finished with filtering, do the ordering
query = query.OrderBy(zz => zz.Field<int>("ID"));

mvc3 dapper No mapping exists from model

I am doing some coding in dapper and I get the error No mapping exists from object type to a known managed provider native type this error occurs on the myfriends var for dapper . I am using dapper to get a list of INT values from a table then comparing them against another.. this is the code that gives me that error
int myid = Convert.ToInt32(User.Identity.Name);
// The var myfriend is giving me that error above
var myfriends = sqlConnection.Query<friend>("Select otherfriendsID from friends where profileID=#myidd", new { myidd = myid }).ToList();
var profiles = sqlConnection.Query<profile>("Select top 40 * from profiles where photo is not null AND profileID=#friendship order by profileID desc", new {friendship=myfriends}).ToList();
however if I use entity everything works fine for instance this code below works..
var myfriends = (from s in db.friends where s.profileID == myid select s.otherfriendsID).ToList();
What could be going on here..
myfriends is a List<friend>. You then pass that in as a query parameter, i.e.
new {friendship=myfriends}
with:
AND profileID=#friendship
Now... what is #friendship ? How should it pass in a List<friend> here? What does that even mean to pass in a list of objects (each of which could have multiple properties) as a single parameter? (note: I'm ignoring table-valued-parameters for the purposes of this question)
So: how many myfriends do you expect? 0? 1? any number? This could be, for example:
var profileIds = myfriends.Select(x => x.ProfileId);
...
new {profileIds}
...
AND profileID in #profileIds
or maybe:
new {profileId = myfriends.Single().ProfileId}
...
AND profileID = #profileId

retrieve all areas where id's don't exist in supplied list

I'm sure I must be missing something really simple here..
OK I have a list of AreaIds. I want to compare that list to the MapArea Table and return any IDs that exist in the table but NOT in the supplied list.
This is my list of supplied areas that I want to check:
var currentAreas = (from c in _entities.mapAreaLink
where c.listingId == id
select new
{
c.MapArea.areaId
}
).ToList();
This is the getting the exhaustive list of mapAreas..
var availableAreas = (from m in _entities.MapAreas
select new
{
m.areaId
}
).ToList();
This compares the two lists and gets items that exist in the maparea table but not in the maparealink (constrained by an id of the item I am looking at).
var unusedAreas = availableAreas.Except(currentAreas).ToList();
I seem to get the list back ok, but what I need to do is now return a list of maparea objects based on the results of the Except.tolist above.
I thought I could do this:
var mapareas = (from e in _entities.MapAreas
where unusedAreas.Contains(e.areaId)
select e).ToList();
I am getting an ambiguous invocation on the where & "Cannot resolve method Contains(int)" on the e.areaId.
Ive tried using:
var unusedAreas = availableAreas.Except(currentAreas).ToArray();
No Joy.. Can anyone help me out here - I am guessing I must be missing a fundamental basic here.
many thanks
You create anonymous types with just one int property. That's not necessary and it causes the later problem. If you create lists of int you'll be OK:
var currentAreas = (from c in _entities.mapAreaLink
where c.listingId == id
select c.MapArea.areaId).ToList();
var availableAreas = (from m in _entities.MapAreas
select m.areaId).ToList();

Linq to entities - searching in EntityCollection navigation properties

We have classes
public Invoice: EntityObject
{
public EntityCollection<InvoicePosition> Positions { get {...}; set{...}; }
...
}
public InvoicePosition: EntityObject
{
public string GroupName { get {...}; set{...}; }
}
We are given IQueryable<Invoice>, we are not given IQueryable<InvoicePosition>. How should I find invoices that have positions, where GroupName is 'Fuel'?
IQueryable<Invoice> invoices = InvoiceRepository.List();
IQueryable<Invoice> invoicesThatHaveFuelPositions =
from i in invoices
where ?
select i
EntityFramework should be able to translate it to proper sql query.
EDIT
As Mark Seemann wrote, I can use:
IQueryable<Invoice> invoices = InvoiceRepository.List().Include("Positions").Include("OtherInclude");
IQueryable<Invoice> invoicesThatHaveFuelPositions =
from i in invoices
from p in i.Positions
where p.GroupName = 'Fuel'
select i;
There is a problem. When I use this filtering, I lose "OtherInclude". I think that this is not proper way of filtering when using EF. I'll have to change it to:
IQueryable<Invoice> invoices = InvoiceRepository.List().Include("Positions").Include("OtherInclude");
IQueryable<Invoice> invoicesThatHaveFuelPositions = invoices.Where(???);
But what should I write in Where?
EDIT
Changed Include("Position") to Include("Positions").
EDIT
Alex James gave link to the tip (http://blogs.msdn.com/alexj/archive/2009/06/02/tip-22-how-to-make-include-really-include.aspx), which suggests:
IQueryable<Invoice> invoicesThatHaveFuelPositions =
from i in invoices
where i.Positions.Any(p => p.GroupName == 'Fuel')
select i;
It seems to work and doesn't influence EF includes.
Building on Marks answer. If you do this:
var q = from i in invoices.Include("something")
from p in i.Positions
where p.GroupName == "Fuel"
select i;
The include is lost (see this tip) because the EF loses all includes if the shape of the query changes, for example if you do implicit joins like in a SelectMany query, aka from from.
The workaround is to write your query, and then at the end apply the Include.
Something like this:
var q = ((from i in invoices
from p in i.Positions
where p.GroupName == "Fuel"
select i) as ObjectQuery<Invoice>).Include("something");
If you do this the Entity Framework actually does the include.
Hope this helps
Alex
Something like this ought to work:
var q = from i in invoices
from p in i.Positions
where p.GroupName == "Fuel"
select i;
However, that uses the navigation property Positions, which by default isn't loaded (the Entity Framework uses explicit loading). It will, however, work, if the invoices variable was created like this:
var invoices = from i in myObjectContext.Invoices.Include("Positions")
select i;

DataTable Query

I am new to LINQ. I am trying to find the rows that does not exists in the second data table.
report_list and benchmark both type are : DataTable. Both these datatables are being populated using OleDbCommand,OleDbDataAdapter. I am getting an error "Specified cast is not valid." in foreach ... loop. I would appreciate your help.
var result = from a in report_list.AsEnumerable()
where !(from b in benchmark.AsEnumerable()
select b.Field<int>("bench_id")
)
.Contains(a.Field<int>("BenchmarkID"))
select a;
foreach (var c in result)
{
Console.WriteLine(c.Field<string>("Name"));
}
I don't know if I understood your question. Are you trying to get the items that exists in the first table but not in the second?
var first = new string[] { "b", "c" };
var second = new string[] { "a", "c" };
//find the itens that exist in "first" but not in "second"
var q = from f in first
where !second.Contains(f)
select f;
foreach (var s in q) {
Console.WriteLine(s);
}
//Prints:
//b
I suggest you to make the inner query first, once it does not depend on the outer record.
From a in report_list
Group Join b in benchmark On a.bench_id Equals b.bench_id Into g = Group
Where g.Count = 0
Select a
Note that this is VB syntax.
My suspicion is that one of the fields you are comparing is not an integer in the database. I believe that the invalid cast exception is being thrown by one of the Field<int>() calls since that is one of the three different exceptions that this method can throw. See docs here.
Perhaps use the .Except() extension to get the set difference of the two sets?
(from b in benchmark.AsEnumerable()
select new { id = b.Field<int>("bench_id")}).Except(
from a in report_list.AsEnumerable()
select new {id = a.Field<int>("BenchmarkID")})
Not actually sure of the precise syntax, but that should work by taking the ids in benchmark, and then removing all equivalent ids in report_list, leaving only the ids that don't match. (I hope this is the order you were after...)
Note: This is also assuming that the above issue mentioned by tvanfosson isn't also a problem

Resources