I have Documents table and Signs table. Document record can be related with many records in Signs table.
Now, I want to get all records of Documents table when document ID appears in Signs table.
Here I get all documents:
var documents = (from c in context.documents select c);
Here I get all my signs and save into List:
var myDocuments = (from s in context.signs where s.UserId== id select s.ID).ToList();
This list contains collection on document ID.
And here, I'm trying to get all documents that exists in myDocuments list:
documents.Where(item => myDocuments.Contains(item.ID));
But, when I do .ToList() allways return all records (in database only exists one compatible record)
What is wrong in LinQ statement?
The problem is that this statement doesn't modify the contents of documents, it merely returns the results (which you're not doing anything with):
documents.Where(item => myDocuments.Contains(item.ID));
documents is still the full list.
Change this line to something like:
var matchingIDDocs = documents.Where(item => myDocuments.Contains(item.ID));
And then use matchingIDDocs in place of "documents" later in your code.
Related
I have a Document table and a Version table. Both have identical information. Whenever a document is created it is inserted into the document table. Whenever that document is then edited a line is added to the Versions table.
It has a field dateApproved which will be null until it is approved. I am currently working on a MVC 4 Approval page and I have never touched linq before and it needs to be done in linq.
How can I join these two tables Document/Version and only show items where dateApproved is null?
from v in Versions
select v
from v in Document
select v
EDIT #1
A user adds a brand new document, this document is then added to the document table. At this point the document needs approval. The dateApproved field in the Documents table is null. Lets say this document gets approved, then the user makes a change and since this document already exists a line is added to the Versions table. Now this document exists in both tables the original document having a revision 0 with a dateApproved, and the Versions table have a revision 1 with a dateApproved as null.
What I need is the documents where the dateApproved is null weather this null is in the Documents table or the Versions table. After it is approved we leave the line in the Version table, and update the line in the Documents table with the approved version.
The key primary key is DocumentID.
EDIT #2
Thanks to Peter Kiss it is now displaying all the files that need to be approved. There is one more hiccup I am running into. It is returning 3 results which is correct. 2 files are brand new and 1 has been edited.
The 2 brand new files it displays the information correctly as from the documents table. The edited file it is displaying the information from the documents table but I need the info from the revisions table. Is it possible to make it return the version table information if the item exists in the version table and return the document table information if it does not exist in the version table (ie brand new).
Hope I explained that properly.
var documents =
ctx.Documents
.Where(x => x.dateApproved == null
|| x.Versions.Any
(y => y.dateApproved == null));
The documents variable will contain only those documents which are having unapproved versions. Then when you iterating through this collection the current document can reach it's Versions (all) through a navigation property called Versions. In that collection you can filter the unapproved versions.
All this only happens when the mapping is set up correctly (aka foreign keys) in your context.
After Edit #2
class DocumentToApprove
{
public string Name { get; set; }
/* other stuff */
public int version { get; set; }
}
var documents = ctx.Documents
.Where(x => x.dateApproved == null
|| x.Versions.Any(y => y.dateApproved == null));
var toApprove = from d in documents
let v = d.Versions.FirstOrDefault(y => y.Approved == null)
select new DocumentToApprove
{ Name = d.Name
,
/* other stuff */
Version = v == null ? 1 : v.VersionNumber
};
Select only records which are having dateApproved is null. and collect it in some kind of list listofVersions.
var listofVersions=(from v in Versions
where v.dateApproved==null
select v).ToList();
You can do the same for Document. Just substitute Version with Document.
Note: I just collect it with var to make it simple. You can create a list of Versions/Document if you wish.
I have a legacy database that has data elements stored as a comma delimited list in a single database field. (I didn't design that, I'm just stuck with it.)
I have a list of strings that I would like to match to any of the individual values in the "array" in the DB field and am not sure how to do this in Linq.
My list:
List<string> items= new List<string>();
items.Add("Item1");
items.Add("Item2");
The DB field "Products" would contain data something like:
"Item1,Item3,Item4"
"Item3,Item5,Item6"
"Item2,Item7,Item6"
"Item1,Item2"
"Item1"
My first pass at the Linq query was:
var results = (from o in Order
.Where(p=> items.Contains(p.Products)
But I know that won't work. because it will only return the records that contain only "Item1" or "Item2". So with the example data above it would return 0 records. I need to have it return two records.
Any suggestions?
There is a simple clever trick for searching comma-separated lists. First, add an extra , to the beginning and end of the target value (the product list), and the search value. Then search for that exact string. So for example, you would search ,Item1,Item3,Item4, for ,Item1,. The purpose of this is to prevent false positives, i.e., Item12,Item3 finding a match for Item1, while allowing items at the beginning/end of the list to be properly found.
Then, you can use the LINQ .Any method to check that any item in your list is a match to the product list, like the following:
var results = (from o in Order
.Where(o => items.Any(i => (","+o.Products+",").Contains(","+i+",")))
One way would be to parse the list in the Products field:
var results = (from o in Order
.Where(o => items.Any(i => o.Products.Split(',').Contains(i))
But that would parse the string multiple times for each record. You could try pulling back ALL of the records, parsing each record once, then doing the comparison:
var results = from o in Order
let prods = o.Products.Split(',')
where items.Any(i => prods.Contains(i))
select o;
I have a dataset (called dataSet below) with a single table and some records in it. One of the columns is called Message and contains an error message. If any records have a value in this field I want to copy it into an error dataset (errorDataSet below) and then remove it from the original dataset. I managed to get this far with LINQ:
DataSet errorDataSet = dataSet.Copy();
//find all records that have a Message column value
var query = from row in errorDataSet.Tables[0].AsEnumerable()
where !String.IsNullOrEmpty(row.Field<string>("Message"))
select row;
DataSet tempErrorDataSet = errorDataSet.Clone();
foreach (var row in query)
{
tempErrorDataSet.Tables[0].Clear();
tempErrorDataSet.Tables[0].ImportRow(row);
utility.WriteError(connectorName, row["Message"].ToString(), tempErrorDataSet);
//remove the error row from the good data
dataSet.Tables[0].Rows.Remove(row);
}
The bottom line throws an exception or I get errors regarding modifying a collection etc. I'm sure there is a simple way of doing this in LINQ.
Note: The reason I have tempErrorDataSet is that I convert it to XML and pass it into a stored proc - it only takes a record at a time in that format, hence I clear it each time.
Your query is enumerating (indirectly) through the rows in the table. As you should already know, you cannot modify a collection (remove something in this case) as you enumerate over it. Throw the contents into a list beforehand. That way you're not enumerating through the actual table but a copy of some rows.
var query = (from row in errorDataSet.Tables[0].AsEnumerable()
where !String.IsNullOrEmpty(row.Field<string>("Message"))
select row).ToList();
db.AdDetails.Where( u => u.OwnerGUID == CurrentUserProviderKey)
I have an adDetails table that has an OwnerGUID field.
I want to pull out only ad details that belong to the currenly logged in user.
My query does not show any where clauses in the SQL when I look at it in the debugger.
Can someone help me figure out what is wrong with my statement and if all rows in the table will be brought back then all 10K records put though a where on the webserver?
I am really new to this.
Using the Where extension method will filter down the results.
Queries in Entity Framweork are not executed until you iterate over them. If you do:
var query = db.Where(u => u.OwnerGUID == key);
This does not execute the query. When you do the following:
var list = list.ToList();
OR
foreach( var item in query) { ... }
That is when the query will be executed in SQL. The results should be filtered with your WHERE clause at this point.
In the table ReservationWorkerPeriods there are records of all workers that are planned to work on a given period on any possible machine.
The additional table WorkerOnMachineOnConstructionSite contains columns workerId, MachineId and ConstructionSiteId.
From the table ReservationWorkerPeriods I would like to retrieve just workers who work on selected machine.
In order to retrieve just relevant records from WorkerOnMachineOnConstructionSite table I have written the following code:
var relevantWorkerOnMachineOnConstructionSite = (from cswm in currentConstructionSiteSchedule.ContrustionSiteWorkerOnMachine
where cswm.MachineId == machineId
select cswm).ToList();
workerOnMachineOnConstructionSite = relevantWorkerOnMachineOnConstructionSite as List<ContrustionSiteWorkerOnMachine>;
These records are also used in the application so I don't want to bypass the above code even if is possible to directly retrieve just workerPeriods for workers who work on selected machine. Anyway I haven't figured out how it is possible to retrieve the relevant workerPeriods once we know which userIDs are relevant.
I have tried the following code:
var userIDs = from w in workerOnMachineOnConstructionSite select new {w.WorkerId};
List<ReservationWorkerPeriods> workerPeriods = currentConstructionSiteSchedule.ReservationWorkerPeriods.ToList();
allocatedWorkers = workerPeriods.Where(wp => userIDs.Contains(wp.WorkerId));
but it seems to be incorrect and don't know how to fix it. Does anyone know what is the problem and how it is possible to retrieve just records which contain userIDs from the list?
Currently, you are constructing an anonymous object on the fly, with one property. You'll want to grab the id directly with (note the missing curly braces):
var userIDs = from w in workerOnMachineOnConstructionSite select w.WorkerId;
Also, in such cases, don't call ToList on it - the variable userIDs just contains the query, not the result. If you use that variable in a further query, the provider can translate it to a single sql query.