Linq To SQL Contains - c#

How can I go about converting this SQL statement to LINQ:
SELECT [Content].[Content], [Content].ListOrder, [Content].ContentTypeId,
[Content].ContentId
FROM [Content] INNER JOIN
GroupContentPermission ON [Content].ContentId = GroupContentPermission.ContentId
WHERE GroupContentPermission.GroupId IN
(SELECT GroupId FROM GroupUser WHERE GroupUser.UserId = 169)

Translation to LINQ is generally pretty straightforward except for one special trick in the case of your query. You can translate your select, where, and from statements in a natural way as shown below. In the case of an IN statement though, you have to get the results from the inner subquery first, and then check if the inner subquery .Contains the value you want to check.
var groups =
(from gu in GroupUser
where gu.UserId == 169
select gu.GroupId).ToList();
var result =
from p in GroupContentPermission
join c in Content on p.ContentId equals c.ContentId
where groups.Contains(p.GroupId)
select new { c.Content, c.ListOrder, c.ContentTypeID, c.ContentId };
// result should contain the same results as the SQL query
Here are some other resources you may find helpful as well (you can find many more resources and tutorials on LINQ if you do a quick google search. There are literally thousands):
Linqer, a SQL to LINQ converter.
LinqPAD, a simple .NET/LINQ tester for rapid experimentation
ScottGu's definitive guide to Using LINQ To SQL
Related SO question: What are some good LINQ resources?, which references a tutorial called 101 LINQ Samples.

Assuming you already link the tables with foreign keys in your model (DBML/EntityFrameworks):
Contents.Where(x => x.GroupContentPermission.GroupUser.UserId == 169).Select(x => new {
x.Content,
x.ListOrder,
x.ContentTypeId,
x.ContentId })
or preferrably just grab the full Content object, and use any column you want:
var contents = Contents.Where(x => x.GroupContentPermission.GroupUser.UserId == 169).ToList();
foreach (var content in contents)
Console.Write(content.Content);

Related

Linq query for Where on the Joined table without needing join

Trying to get a linq query (or lambda syntax) for the following SQL which Selects all "Data" which in the joining table have an Attribute equal to "blob".
EXCEPT: without explictly using the Join, but the
select data.*
from data
join settings on data.DataID = settings.DataID
where settings.Attribute = 'blob'
Explicitly defining the join
from d in dbcontext.Data
join s in dbcontext.Settings on d.DataID equals s.DataID
where s.Attribute == "blob"
select d
but is there a way to use the context dbcontext.Data.Settings
like the following?
from d in dbcontext.Data
where d.Settings.Attribute == "blob"
select d
Settings is a collection Type, so things like .Contains, and .Where come to mind.
using .Contains, my understanding is i would need to pass in an object type
where d.Settings.Contains(new Settings(d.DataID, "blob", null))
but i dont care about the null (Value) matching, just column Settings
some table structures
Data
DataID
Name
Settings
DataID
Attribute
Value
As I understand, you have Settings collection navigation property, so instead of explicit join you could simply use it ("navigate"):
from d in dbcontext.Data
from s in d.Settings
where s.Attribute == "blob"
select d
Alternatively you could use Any extension method which in this case is more appropriate than Contains (although Contains can also be used, but needs to be combined with Select):
dbcontext.Data.Where(d => d.Settings.Any(s => s.Attribute == "blob"))
For completeness, here is the Contains version:
dbcontext.Data.Where(d => d.Settings.Select(s => s.Attribute).Contains("blob"))
If I understand your question correctly, you want to create a LINQ that will grab any DataID that has an attribute of of "Blah" that is stored in another table.
If so this may work.
var dataIDs = Setting.Where(entry => entry.Attribute == "Blah")
.Select(entry => entry.DataID); // gets all DataIDs that match the attribute
var data = Data.Where(entry => entry.DataID in dataIDs); // gets data info based on DataIDs.
It should work, but what you should do instead is do an left join somewhat like
select a.*
from data a
left join settings b
on a.DataID = b.DataID
where b.Attribute = 'blob'
but in LINQ. This query would allow you to fetch all the data for DataIDs that match attribute 'blob. I haven't done it in LINQ so if someone more familiar with left joins with linq could respond that might work better

Build Where Clause (not sure PredicateBuilder will work for me)

I am trying to query a database using LINQ. I am joining TableA with TableB with TableC.
I have zero to many 'keywords' (don't know how many at design time) that I would like to look for within (LIKE '%%') several fields that are spread across the three tables.
Assuming three (3) keywords are entered into my search box:
In T-SQL I would have this -
SELECT tbl0.FieldA, tbl0.FieldB, tbl1.FieldC, tbl1.FieldD, tbl2.FieldE, tbl2.FieldF
FROM tbl0
JOIN tbl1 ON tbl0.KeyField = tbl1.KeyField
JOIN tbl2 ON tbl1.KeyField = tbl2.KeyField
WHERE (tbl0.FieldA LIKE '%{keyword1}%' OR tbl1.FieldC LIKE '%{keyword1}%' OR tbl2.FieldE LIKE '%{keyword1}%' OR tbl0.FieldA LIKE '%{keyword2}%' OR tbl1.FieldC LIKE '%{keyword2}%' OR tbl2.FieldE LIKE '%{keyword2}%' OR tbl0.FieldA LIKE '%{keyword3}%' OR tbl1.FieldC LIKE '%{keyword3}%' OR tbl2.FieldE LIKE '%{keyword3}%')
Question is -- How do I 'dynamically' build this WHERE clause in LINQ?
NOTE #1 -- I do not (for reasons outside the scope of this question) want to create a VIEW across the three tables
NOTE #2 -- Because I am joining in this way (and I am still new to LINQ) I don't see how I can use the PredicateBuilder because I am not sure what TYPE (T) to pass into it?
NOTE #3 -- If it matters ... I am ultimately planning to return a strongly typed list of (custom) objects to be displayed in a GridView.
EDIT - 8/17/2012 - 5:15 PM EDT
The comment below is correct.
"The code the OP is looking for is where any one of the fields contains any one of the keywords."
Thanks everyone!
Here's a solution not using the PredicateBuilder. Just get all the items containing the first keyword and merge it with all the items containing the second keyword and so on. Not knowing anything about the context of the problem I can't tell if this will be efficient or not.
var query = from t0 in db.Table0
join t1 in db.Table1 on t0.KeyField equals t1.KeyField
join t2 in db.Table2 on t1.KeyField equals t2.KeyField
select new
{
t0.FieldA, t0.FieldB,
t1.FieldC, t1.FieldD,
t2.FieldE, t2.FieldF
};
string keyword = keywordsList[0];
var result = query.Where(x => x.FieldA.Contains(keyword) ||
x.FieldC.Contains(keyword) ||
x.FieldE.Contains(keyword));
for (int i = 1; i < keywordsList.Length; i++)
{
string tempkey = keywordsList[i];
result = result.Union(query.Where(x => x.FieldA.Contains(tempkey) ||
x.FieldC.Contains(tempkey) ||
x.FieldE.Contains(tempkey)));
}
result = result.Distinct();

Using the equivalent to the SQL IN function with LINQ with a collection

How do I translate the following in LINQ?
SELECT DISTINCT w.Worker_ID, w.Surname, w.FirstName, ps.JobNumber
FROM Worker w, ProjectSignatory ps
where w.Worker_ID = ps.Worker_ID
and ps.JobNumber
IN
(SELECT DISTINCT pa.JobNumber
FROM Worker w, PAAFRegister pa
where w.Worker_ID = pa.Worker_ID
and w.Worker_ID = #UserX)
I have seen anumber of posts which sugges that the .Contains function is a good idea, however since I am looking through a collection of results then based from what I have seen on other responses LINQ does not like it when people call .Contains on a collection.
I am trying to understand the workings of LINQ on the whole. I am relatively inexperienced. Any advice would be greatly appreciated.
EDIT: I have seen a few approaches and I am wondering if the following is a good start or would it be best achieved using a linge query using joins?
var sig = from w in db.Workers
join ps in db.ProjectSignatories
on w.Worker_ID equals ps.Worker_ID
select ps;
var paaf = from w in db.Workers
join pa in db.PAAFRegisters
on w.Worker_ID equals pa.Worker_ID
where w.Worker_ID == workerID
select w;
I am aware that this is incomplete and seves no purpose or makes no sense to what I am attempting to achieve. This was merely an example based on previous posts I have seen and wondering if the approach is suitable.
Thanks!
You're looking for the .Contains() function.
First build up the inner filter set section of the query.
E.G.: The part that goes in the .Contains() (in SQL terms the "ps.JobNumber IN (...)" )
Filter your query by the new data subset by using the .Contains function.
Example:
C# SQL-like syntax:
var subSet = select JobNumber
from Workers
where Worker_ID == "UserX";
var result = select JobNumber
from Workers
where subSet.Contains(jobnumber);
LINQ chaining:
var subSet = Workers.Where(o => o.Worker_ID == "UserX")
.Select(o => o.JobNumber)
.Distinct();
var result = Workers.Where(o => subSet.Contains(o.JobNumber)).ToList();
You can create subselect's in LINQ.
var jobNumbers = select JobNumber from Workers where <your criteria, joins>
var myResult = select JobNumber from Workers where <your criteria, joins> and jobNumbers.Contains(JobNumber)

Marc Gravell's Dynamic OrderBy works in one case but not in other

I am trying to do a dynamic order by on columns using Marc Gravell's code. I am posting the 2 queries. It works in one case but doesn't work in 2nd case. Can anybody tell me what changes I need to make to make both queries run perfectly?
This is the link to the Marc Gravell's answer:
https://stackoverflow.com/a/233505
I am using Northwind database. These are both my queries:
var query = (from cust in northwindEntities.Customers
select new
{
City = cust.City ,
Orders = northwindEntities.Orders
.Where(o => o.CustomerID == cust.CustomerID)
.OrderBy("OrderID")
}); // doesn't work.
var query = (from cust in northwindEntities.Customers
select new
{
City = cust.City ,
//Orders = northwindEntities.Orders.Where(o => o.CustomerID == cust.CustomerID).
// OrderBy("OrderID")
}).OrderBy("City"); // works
Here is the exception of the 1st query:
LINQ to Entities does not recognize the method
'System.Linq.IOrderedQueryable1[ConsoleApplication12.Order]
OrderBy[Order](System.Linq.IQueryable1[ConsoleApplication12.Order],
System.String)' method, and this method cannot be translated into a
store expression.
You need to order the final set of result, like you do it in the second case. In first case you order only northwindEntities.Orders.Where( result and not final one.
The correct query is the second.
Obviously it would not work because of the same reason as
var query = (from cust in northwindEntities.Customers
select new
{
City = cust.City ,
Orders = northwindEntities.Orders
.MyCustomMethod()
});
will not work. LINQ-to-Entities will walk through this expression tree and try to convert it to SQL. It can work on known sub set of methods to translate to SQL.
But in the second query, custom OrderBy method dynamically creates the OrderBy that LINQ-to-Entities knows.

Linq to SQL - Query

I am trying to mimic below statement in Linq to SQL.
WHERE (rtrim(posid) like '%101' or rtrim(posid) like '%532')
I statement basically determine if posid ends with 101 or 532. In the above example I am only making 2 comparisons but their could be 1 to N comparisons all joined with OR. I store the comparison values (101,532,...) in a generic list that I send to my Linq to SQL method.
I have tried to mimic above SQL using a where clause unsuccessfully (example below):
var PosNum = new List<string>();
PosNum.Add("101");
PosNum.Add("532");
var q = (from a in context.tbl_sspos select a);
q = q.Where(p => PosNum.Contains(p.posid.Trim()));
The issue with the above where clause is that it tries to do an exact match rather I want an ends with comparison.
How would I mimic the SQL statement in Linq to SQL.
Thank You in advance for any help / advice you can provide.
I would use String.EndsWith();
This will check the end of the string rather than entire contents of it.
var q = (from a in context.tbl_sspos select a);
q = q.Where(p => p.posid.EndsWith("102") || p.posid.EndsWith("532"));
In EF 4 you can use the StartsWith / EndsWith methods by now. Might also work in LINQ to SQL.
UPDATE
Just realized that you are trying todo this against multiple values (PosNum), I don't think that this is directly supported currently. You can however concatenate multiple Where()clauses to get the result.
UPDATE 2
As AdamKing pointed out concatenating the where clauses was filtering against all PosNum values, here is the corrected version:
var baseQuery = (from a in context.tbl_sspos select a);
IEnumerable<YourType> q = null;
foreach(var pos in PosNum)
{
if(q == null)
q = baseQuery.Where(a => a.posid.EndsWith(pos));
else
q = q.Union(baseQuery.Where(a => a.posid.EndsWith(pos)));
}
This is not as pretty anymore, but works nonetheless.

Categories