LINQ to SQL: How to implement a LEAST or similar function? - c#

Given:
A table named TABLE_1 with the following columns:
ID
ColumnA
ColumnB
ColumnC
ColumnD
I have SQL query where TABLE_1 joins on itself twice based off of ColumnA, ColumnB, ColumnC. The query might look something like this:
Select t1.ID, t2.ID, t3.ID, LEAST(t1.ColumnD, t2.ColumnD, t3.ColumnD)
From TABLE_1 t1
Left Join TABLE_1 t2 On
t1.ColumnA = t2.ColumnA
And t1.ColumnB = t2.ColumnB
And t1.ColumnC = t2.ColumnC
Left Join TABLE_1 t3 On
t2.ColumnA = t3.ColumnA
And t2.ColumnB = t3.ColumnB
And t2.ColumnC = t3.ColumnC
Problem:
I need that Query to be rewritten in LINQ. I've tried taking a stab at it:
var query =
from t1 in myTABLE1List // List<TABLE_1>
join t2 in myTABLE1List
on new {t1.ColumnA, t1.ColumnB, t2.ColumnC}
equals new {t2.ColumnA, t2.ColumnB, t2.ColumnC}
join t3 in myTABLE1List
on new {t2.ColumnA, t2.ColumnB, t2.ColumnC}
equals new {t3.ColumnA, t3.ColumnB, t3.ColumnC}
select new {
ID_1 = s1.ID,
ID_2 = s2.ID,
ID_3 = s3.ID,
// Invalid anonymous type member declarator.
// Anonymous type members must be declared with a member assignment,
// simple name or member access.
// how can I implement this?
least(s1.ColumnD, s2.ColumnD, s3.ColumnD)
};
....
private object least(params object[] objects)
{
// code here that sorts the objects and returns the 'smallest' of them.
return leastObject;
}
How do I write my query in LINQ? What am I doing wrong? I thought it was possible to use functions inside of LINQ expressions, so why am I getting this error?

I could be wrong, but I think you need to assign the result of least to an actual member of your new anonymous type instance, e.g.:
select new {
ID_1 = s1.ID,
ID_2 = s2.ID,
ID_3 = s3.ID,
Least = least(s1.ColumnD, s2.ColumnD, s3.ColumnD)
};

How about?
MinOfColumnD = Math.Min(Math.Min(s1.ColumnD, s2.ColumnD), s3.ColumnD))
EDIT: Assuming that ColumnD in each of the table is numeric & 'least` (in this context) is minimum of 3 numbers in the given columns.
EDIT: If the columns are string, determine what max. values it can hold & do a .Parse on it.
For e.g.
MinOfColumnD = Math.Min(Math.Min(int.Parse(s1.ColumnD), int.Parse(s2.ColumnD)), int.Parse(s3.ColumnD)))

Related

How to select all columns in LINQ Datatable join?

var collection = from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable()
on t1["id"] equals t2["id"]
select new { Name = t1["name"], Group = t2["group"] };
I want to select all columns of both table like join in SQL Server inner join query.
In Addition
How can i convert whole result of both tables to data-table?
var collection = from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable()
on t1["id"] equals t2["id"]
select new { T1 = t1, T2 = t2 };
then...
EDIT:
Something along those lines
//clone dt1, copies all the columns to newTable
DataTable newTable = dt1.Clone();
//copies all the columns from dt2 to newTable
foreach(var c in dt2.Columns)
newTable.Columns.Add(c);
//now newTable has all the columns from the original tables combined
//iterates over collection
foreach (var item in collection) {
//creates newRow from newTable
DataRow newRow = newTable.NewRow();
//iterate the columns, gets values from either original table if column name is there
foreach(var c in newTable.Columns)
newRow[c.ColumnName] = item.T1.ContainsColumn(c.ColumnName) ? item.T1[c.ColumnName] : item.T2[c.ColumnName];
newTable.Rows.Add(newRow);
}
This will work. But if dt1 and dt2 share multiple columns with the exact same name, you might have some loss of data.
While you can't expand them to columns, you can simply return the entities. Eg:
select new { CTLJCRJOB, CTLRFDSTM }
If you need it flattened, then you will have to write out the mapping yourself, but will still be very trivial.
Referenced from:
Select All columns for all tables in join + linq join
ou have to specify each manually if you want to project into a flattened type. Your other option is to just have your combined type contain both objects, and the objects will naturally bring along their properties.
select new
{
Object1 = object1,
Object2 = output
};
And you would work with it like myObj.Object1.Property1, myObj.Object2.Property4, etc.
One final option that still involves some manual work is to define an appropriate type and have a constructor or a builder method that does the work of segmenting out your object properties into a flattened type. You still perform the manual mapping, but you isolate it from your query logic.
select new CombinedType(object1, output);
//or
select builder.GetCombinedType(object1, output);
Referenced From
Select all columns after JOIN in LINQ
var collection = (from t1 in dt1.AsEnumerable()
join t2 in dt2.AsEnumerable()
on t1 ["id"] equals t2 ["id"]
select new { Name = t1 ["name"], Group = t2 ["group"] }).ToList() ;
Hope this will help

Linq Simple query error

I am writing a simple query in LINQ. In fact it is my first query in Linq. How the query is interpreted by compiler confused me. My query is not giving any result.
My Linq Query:
using (DataClasses1DataContext db = new DataClasses1DataContext(("connection string")))
{
var notif_sched_data = from sched in db.NOTIF_SCHEDs
join recip in db.NOTIF_RECIPs
on sched.NOTIF_RECIP_ID equals recip.NOTIF_RECIP_ID
select sched.NOTIF_RPT_ID;
}
which is interpreted by compiler as
SELECT [t0].[NOTIF_RPT_ID]
FROM [dbo].[NOTIF_SCHED] AS [t0]
INNER JOIN [dbo].[NOTIF_RECIP] AS [t1] ON [t0].[NOTIF_RECIP_ID] = [t1].[NOTIF_RECIP_ID]
and it gives no row as output. However,the SQL which is correctly working is :
select [NOTIF_SCHED].[NOTIF_RPT_ID]
from [NOTIF_SCHED]
INNER JOIN [NOTIF_RECIP] on [NOTIF_RECIP].[NOTIF_RECIP_ID]=[NOTIF_SCHED].[NOTIF_RECIP_ID].
Can somebody tell me what I need to change?
if i change the value around equals,it gives error as value is not in the right scope.
You are not materializing the query in anyway. the query will return you IQueryable of what you are selecting there. To get the query actually executed to the database you need to materialize the results with methods like .Count(), .FirstOrDefault(), .Tolist(), etc...
using (var db = new DataClasses1DataContext(("connection string")))
{
var query = (from sched in db.NOTIF_SCHEDs
join recip in db.NOTIF_RECIPs
on sched.NOTIF_RECIP_ID equals recip.NOTIF_RECIP_ID
select sched.NOTIF_RPT_ID);
var count = query.Count();
var list = query.ToList();
}
Thanks for your time. Actually query was correct. The problem was in the class file where we convert sql objects in OOPS objects.
i think the problem is for the last line.you should create a new anonymous type.so changing the last line to this may solve the problem :
select new { sched.NOTIF_RPT_ID };
also you can create a class like this one and set your values to an object of the class
public class data
{
public int id {get;set}
public somthing somthing {get;set}
...
}
now simply :
select new { id = sched.NOTIF_RPT_ID , something = x , ... };

Multiple on clause in LINQ to DataTable Join Query

So I have two DataTables that have the same schema, but different data. I want to join the two tables together where two fields, id3 and print and the same. How would I write this in LINQ?
Right now, this works and gives no compiler errors:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on prod.Field<string>("print") equals agg.Field<string>("print")
select new
{
print = prod.Field<string>("print")
};
But what I really want is this:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on (prod.Field<string>("print") equals agg.Field<string>("print") &&
prod.Field<Int32>("id3") equals agg.Field<Int32><("id3"))
select new
{
print = prod.Field<string>("print")
};
But this gives me compiler errors.
How do I join these two tables together on both the print and the id3 columns?
Regards,
Kyle
Use anonymous objects to join on multiple fields:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on new {
Print = prod.Field<string>("print"),
Id3 = prod.Field<Int32>("id3")
} equals new {
Print = agg.Field<string>("print"),
Id3 = agg.Field<Int32>("id3")
}
select new {
print = prod.Field<string>("print")
};
Keep in mind that anonymous object property names should match.

Most efficient way to get MAX value of joined table in LINQ query using C#

I am trying to find the most efficient way to get the most recent record in a joined table in LINQ.
This query may handle thousands of records so I didn't want to perform a subquery.
I need everything from items, but only the most recent date from the "Notes" table, whose field name is SubmittedDate.
var items = (from t1 in db.Items
from t2
in db.Notes
.Where(o => (t1.Item_ID == o.Item_ID))
select new ItemModel
{
Name = t1.Name,
MostRecentUpdate = t2.SubmittedDate <== Need max value in model
});
Any help would be greatly appreciated.
It looks like you probably just want a group join:
var items = from t1 in db.Items
join t2 in db.Notes on t1.Item_ID equals t2.Item_ID into notes
select new ItemModel
{
Name = t1.Name,
MostRecentUpdate = notes.Max(x => (DateTime?) x.SubmittedDate)
};
Now MostRecentUpdate should be null if there are no non-null dates in the matching Notes rows. At least, that's what the LINQ to Objects behaviour would be, so fingers crossed the abstraction holds...

error with linq join

I have this linq query:
var segreterie = from s in db.USR_Utenti join h in db.USR_Accounts
on new {s.ID, settings.GruppoSegreteria}
equals new {h.USR_UtentiReference,h.ID_Gruppo} select s;
that has this problem:
The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.
how can i do to solve it?
The two types should be the same - which means they'll need the same property names as you're using anonymous types. Try this:
var segreterie = from s in db.USR_Utenti join h in db.USR_Accounts
on new {s.ID, Groups = settings.GruppoSegreteria}
equals new {ID = h.USR_UtentiReference, Groups = h.ID_Gruppo}
select s;
That's assuming that s.ID and h.USR_UtentiReference have the same type, and settings.GruppoSegreteria and h.ID_Gruppo do likewise.
On a similar note, if you are doing a join on a field which is nullable (for e.g., int and int?) you may have to do something like (where Field2 is int? in Table1 and int in Table2):
from l in Table1
join l2 in Table2
on new { l.Field1, Field2 = (l.Field2.Value == null ? -1 : l.Field2.Value) } equals new { l2.Field1, Field2 = l2.Field2 }

Categories