How would the following be converted to LINQ-EF
select Name
from TableA as TableAOuter
group by TableAOuter.Name, TableAOuter.Id
having(
select count(TableAInner.Id)
from TableA as TableAInner
where TAbleAInner.Reference=TableAOuter.Id) = 0
);
To me, that looks like:
var query = from row in tableOuter
group row by new { row.Name, row.Id } into g
where !tableInner.Any(inner => inner.Reference == g.Key.Id)
select g.Key.Name;
Although I'd be tempted to perform the filtering before the grouping - at which point you can just group the row name:
var query = from row in tableOuter
where !tableInner.Any(row => inner.Reference == row.Id)
group row.Name by new { row.Name, row.Id };
I think that should do the same thing, right?
Related
I have the following query:
var query = (from wo in _dbContext.WorkOrder
join opr in _dbContext.Operation
on wo.operationID equals opr.operationID
where wo.orderid == selectedorderid
select new {wo.orderid, wo.workOrderID, wo.itemID, wo.operationID, opr.operationName, wo.operationCode}).ToList();
I also have another table,which joins with workorder table,and returns multiple values.
What I want to do is,I want to join the table and get a single column of it as a concentrated column in my query such as (id1,id2,id3) etc. How can I achieve this?
What about:
var query = (from wo in _dbContext.WorkOrder
join opr in _dbContext.Operation
on wo.operationID equals opr.operationID
where wo.orderid == selectedorderid
select new {wo.orderid, wo.workOrderID, wo.itemID, wo.operationID, opr.operationName, wo.operationCode}).ToList();
var orders = queryGroupBy(i => i.workOrderID)
.Select(i => new {WorkOrderId = i.workOrderID, ConcatinatedIds = String.Join(", ", i.Select(j => j.operationID))})
.ToList();
I want to use Linq to select and group DataTable rows... and I want to order those in a descending manner by the "Max" created date in each group... are there any improvements that could be made to this code, in particular can I make the OrderByDescending part of the Linq, for example using:
orderby {... something here...} descending
--- current code ---
DataTable dt = ReadDataTable();
var rows = (from row in dt.AsEnumerable()
where row.Field<bool>("Active") == true
group row by new
{
CollectionId = row.Field<int>("CollectionId"),
CollectionName = row.Field<string>("CollectionName"),
} into grp
select new
{
CollectionId = grp.Key.CollectionId,
CollectionName = grp.Key.CollectionName,
MaxCreated = grp.Max(r => r.Field<DateTime>("Created"))
}).OrderByDescending(r => r.MaxCreated);
You can use the let clause to hold intermediate results in a complex LINQ query, for use in subsequent sorts and selects. In your case you can use it to store the final result for subsequent sorting.
I.e. you can rewrite your Linq without the OrderByDescending() lambda as follows:
DataTable dt = ReadDataTable();
var rows = from row in dt.AsEnumerable()
where row.Field<bool>("Active")
group row by new
{
CollectionId = row.Field<int>("CollectionId"),
CollectionName = row.Field<string>("CollectionName"),
} into grp
let result = new
{
CollectionId = grp.Key.CollectionId,
CollectionName = grp.Key.CollectionName,
MaxCreated = grp.Max(r => r.Field<DateTime>("Created")),
}
orderby result.MaxCreated descending
select result;
Using Entity Framework Version=6.0.0.0 to get to get common id and orderid as shown below.
var dt1 = from p in dt.AsEnumerable()
select new
{
Id = p.Field<int>("Id"),
OrderId = p.Field<int>("OrderId")
};
var dt2 = (from order in db.Orders
select new
{
order.Id,
order.OrderId
}).ToList();
var intersect = dt1.Intersect(dt2);
Based on the list of values in intersect. I need to select all the values from Orders Table.
Trying to used code getting error "unable to create a constant value of type anonymous type only primitive types"
var result= (from a in sync.Orders
where intersect.Any(b => a.Id == b.Id && a.OrderId == b.OrderId)
select a).ToList();
You are trying to "join" an EF query with an in-memory data set, which does not work because there's not a way to embed the list and the lookup in SQL. One option is to pull the entire table into memory with AsEnumerable:
var result= (from a in sync.Orders.AsEnumberable
where intersect.Any(b => a.Id == b.Id && a.OrderId == b.OrderId)
select a).ToList();
Another option is to concatenate the Id and OrderId into one value and use Contains since that can be translated to an IN clause in SQL:
var lookup = intersect.Select(i => i.Id + "-" + i.OrderId).ToList();
var result= (from a in sync.Orders
where lookup.Contains(a.Id + "-" + a.OrderId)
select a).ToList();
I'm trying to do a left join, not an inner join in a linq query. I have found answers related to using DefaultIfEmpty() however I can't seem to make it work. The following is the linq query:
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id
where a.Table1_id == id
orderby a.sort descending
group e by new
{
a.Field1,
a.Field2
} into ga
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects = (from g in ga select new SubObject{
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
The query only gives me the rows from table 1 that have a corresponding record in table 2. I would like every record in table 1 populated into MyObject and a list of 0-n corresponding records listed in manySubObjects for each MyObject.
UPDATE:
I tried the answer to the question that is a "possible duplicate", mentioned below. I now have the following code that does give me one record for each item in Table1 even if there is no Table2 record.
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id into j1
from j2 in j1.DefaultIfEmpty()
where a.Table1_id == id
orderby a.sort descending
group j2 by new
{
a.Field1,
a.Field2
} into ga
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects = (from g in ga select new SubObject{
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
However, with this code, when there is no record in table2 I get "manySubObject" as a list with one "SubObject" in it with all null values for the properties of "SubObject". What I really want is "manySubObjects" to be null if there is no values in table2.
In reply to your update, to create the null listing, you can do a ternary in your assignment of manySubObjects.
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects =
(from g in ga select g).FirstOrDefaut() == null ? null :
(from g in ga select new SubObject {
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
Here is a dotnetfiddle that tries to do what you're attempting. https://dotnetfiddle.net/kGJVjE
Here is a subsequent dotnetfiddle based on your comments. https://dotnetfiddle.net/h2xd9O
In reply to your comments, the above works with Linq to Objects but NOT with Linq to SQL. Linq to SQL will complain that it, "Could not translate expression ... into SQL and could not treat as a local expression." That's because Linq cannot translate the custom new SubObject constructor into SQL. To do that, you have to write more code to support translation into SQL. See Custom Method in LINQ to SQL query and this article.
I think we've sufficiently answered your original question about left joins. Consider asking a new question about using custom methods/constructors in Linq to SQL queries.
I think the desired Result that you want can be given by using GroupJoin()
The code Below will produce a structure like so
Field1, Field2, List < SubObject > null if empty
Sample code
var query = dc.Table1.Where(x => Table1_id == id).OrderBy(x => x.sort)
.GroupJoin(dc.Table2, (table1 => table1.Table1_id), (table2 => table2.Table2_id),
(table1, table2) => new MyObject
{
field1 = table1.Field1,
field2 = table1.Field2,
manySubObjects = (table2.Count() > 0)
? (from t in table2 select new SubObject { fielda = t.fielda, fieldb = t.fieldb}).ToList()
: null
}).ToList();
Dotnetfiddle link
UPDATE
From your comment I saw this
ga.Select(g = > new SubObject(){fielda = g.fielda, fieldb = g.fieldb})
I think it should be (depends on how "ga" is built)
ga.Select(g => new SubObject {fielda = g.fielda, fieldb = g.fieldb})
Please update your question with the whole query, it will help solve the issue.
** UPDATE BIS **
sentEmails = //ga.Count() < 1 ? null :
//(from g in ga select g).FirstOrDefault() == null ? null :
(from g in ga select new Email{
email_to = g.email_to,
email_from = g.email_from,
email_cc = g.email_cc,
email_bcc = g.email_bcc,
email_subject = g.email_subject,
email_body = g.email_body }).ToList()
Should be:
sentEmails = //ga.Count() < 1 ? null :
((from g in ga select g).FirstOrDefault() == null) ? null :
(from g in ga select new Email{
email_to = g.email_to,
email_from = g.email_from,
email_cc = g.email_cc,
email_bcc = g.email_bcc,
email_subject = g.email_subject,
email_body = g.email_body }).ToList()
Checks if the group has a First, if it doesn't the group doesn't have any records so the Action.Name for a Time Stamp has no emails to send. If the First isn't null the loop throw the group elements and create a list of Email,
var results =
(
// Use from, from like so for the left join:
from a in dc.Table1
from e in dc.Table2
// Join condition goes here
.Where(a.Id == e.Id)
// This is for the left join
.DefaultIfEmpty()
// Non-join conditions here
where a.Id == id
// Then group
group by new
{
a.Field1,
a.Field2
}
).Select(g =>
// Sort items within groups
g.OrderBy(item => item.sortField)
// Project required data only from each item
.Select(item => new
{
item.FieldA,
item.FieldB
}))
// Bring into memory
.ToList();
Then project in-memory to your non-EF-model type.
How do you use LINQ (C#) to select the value in a particular column for a particular row in a datatable. The equivalent SQL would be:
select NAME from TABLE where ID = 0
Thanks for your answers. I didn't understand what type of object "MyTable" was (in your answers) and the following code gave me the error shown below.
DataTable dt = ds.Tables[0];
var name = from r in dt
where r.ID == 0
select r.Name;
Could not find an implementation of the query pattern for source type
'System.Data.DataTable'. 'Where' not found
So I continued my googling and found something that does work:
var rowColl = ds.Tables[0].AsEnumerable();
string name = (from r in rowColl
where r.Field<int>("ID") == 0
select r.Field<string>("NAME")).First<string>();
What do you think?
var name = from r in MyTable
where r.ID == 0
select r.Name;
If the row is unique then you could even just do:
var row = DataContext.MyTable.SingleOrDefault(r => r.ID == 0);
var name = row != null ? row.Name : String.Empty;
I notice others have given the non-lambda syntax so just to have this complete I'll put in the lambda syntax equivalent:
Non-lambda (as per James's post):
var name = from i in DataContext.MyTable
where i.ID == 0
select i.Name
Equivalent lambda syntax:
var name = DataContext.MyTable.Where(i => i.ID == 0)
.Select(i => new { Name = i.Name });
There's not really much practical difference, just personal opinion on which you prefer.
If the return value is string and you need to search by Id you can use:
string name = datatable.AsEnumerable().Where(row => Convert.ToInt32(row["Id"]) == Id).Select(row => row.Field<string>("name")).ToString();
or using generic variable:
var name = datatable.AsEnumerable().Where(row => Convert.ToInt32(row["Id"]) == Id).Select(row => row.Field<string>("name"));
var name = from DataRow dr in tblClassCode.Rows where (long)dr["ID"] == Convert.ToInt32(i) select (int)dr["Name"]).FirstOrDefault().ToString()
var x = from row in table
where row.ID == 0
select row
Supposing you have a DataTable that knows about the rows, other wise you'll need to use the row index:
where row[rowNumber] == 0
In this instance you'd also want to use the select to place the row data into an anonymous class or a preprepared class (if you want to pass it to another method)
Use linq and set the data table as Enumerable and select the fields from the data table field that matches what you are looking for.
Example
I want to get the currency Id and currency Name from the currency table where currency is local currency, and assign the currency id and name to a text boxes on the form:
DataTable dt = curData.loadCurrency();
var curId = from c in dt.AsEnumerable()
where c.Field<bool>("LocalCurrency") == true
select c.Field<int>("CURID");
foreach (int cid in curId)
{
txtCURID.Text = cid.ToString();
}
var curName = from c in dt.AsEnumerable()
where c.Field<bool>("LocalCurrency") == true
select c.Field<string>("CurName");
foreach (string cName in curName)
{
txtCurrency.Text = cName.ToString();
}