How to get columns of both datatable after innerjoining them using linq - c#

My linq is like below
from dt1 in dsResults.Tables[0].AsEnumerable()
join dt2 in dsResults.Tables[1].AsEnumerable()
on dt1 .Field<decimal>("RecordId") equals dt2.Field<decimal>("RecordId2")
select dt1 ;
This will retrieve only columns of dt1 . How can i make columns of both table appear ?

I could do this as below follwing the thread
Create combined DataTable from two DataTables joined with LINQ. C#
DataTable targetTable = dsResults.Tables[0].Clone();
var dt2Columns = dsResults.Tables[1].Columns.OfType<DataColumn>().Select(dc =>
new DataColumn(dc.ColumnName, dc.DataType, dc.Expression, dc.ColumnMapping));
targetTable.Columns.AddRange(dt2Columns.ToArray());
var rowData =
from row1 in dsResults.Tables[0].AsEnumerable()
join row2 in dsResults.Tables[1].AsEnumerable()
on row1.Field<decimal>("RecordId") equals row2.Field<decimal>("RecordId2")
select row1.ItemArray.Concat(row2.ItemArray).ToArray();
foreach (object[] values in rowData)
targetTable.Rows.Add(values);

you could create an object representing the columns you want to show then you can do the below:
public class YourObject
{
public string Pror1 {get;set;}
public string Pror2 {get;set;}
}
List<YourObject> result=from row1 in dsResults.Tables[0].AsEnumerable()
join row2 in dsResults.Tables[1].AsEnumerable()
on row1.Field<decimal>("RecordId") equals row2.Field<decimal>("RecordId2")
select new YourObject()
{
Pror1=row1.prop1,
Prop2=row2.prop2,
......
}.ToList();
if you want to select all the column you can do the below
from row1 in dsResults.Tables[0].AsEnumerable()
join row2 in dsResults.Tables[1].AsEnumerable()
on row1.Field<decimal>("RecordId") equals row2.Field<decimal>("RecordId2")
select new { RowTable1 = row1, RowTable2 = row2}; //anonymous type
In this case each element of the result will have two properties: RowTable1 will be a row from row1, and RowTable2 will be the matching row from row2

1 You can adjust you select clause with anonymous type , and inclue your needed columns with Field properties
from dt1 in dsResults.Tables[0].AsEnumerable()
join dt2 in dsResults.Tables[1].AsEnumerable()
on dt1 .Field<decimal>("RecordId") equals dt2.Field<decimal>("RecordId2")
select new
{
Property1 = dt1 .Field<decimal>("RecordId"),
Property2 = dt2 .Field<decimal>("RecordId2")
......
}
;
2 If you don't want specify column name
from dt1 in dsResults.Tables[0].AsEnumerable()
join dt2 in dsResults.Tables[1].AsEnumerable()
on dt1 .Field<decimal>("RecordId") equals dt2.Field<decimal>("RecordId2")
select new
{
dt1,
dt2
}
;
3 If you want set Union between your sequence
Link : http://msdn.microsoft.com/en-us/library/bb386993.aspx

public string ShowNew(string myName)
{
RENTALEntities objD = new RENTALEntities();
var NewObj =
(from t in objD.TENANTs.ToList()
join pt in objD.PROP_TYPE.ToList()
on t.Prop_ID equals pt.Prop_ID
where t.Surname == myName
select new { t.Surname, t.PropAdress, pt.DESCRIPTION, t.RentalIncome }).First();
return "SWurname" + NewObj.Surname + "<br/>"
+ "Address" + NewObj.PropAdress + "<br/>"
+ "Description" + NewObj.DESCRIPTION + "<br/>"
+ "Rental income" + NewObj.RentalIncome;
}

Related

C# - Copy rows from one DataTable by comparing with 2nd DataTable to 3rd DataTable

I have 4 DataTables in my C# code;
DataTable dt1;
DataTable dt2;
DataTable dt3;
DataTable dt4;
dt1 has following records
Id | Name | City
----------------
1 | Abc | Khi
2 | XYZ | Hyd
3 | TVW | Lhr
4 | tyz | Isb
dt2 has just ID records
Id
---
2
4
I need to copy only rows from dt1 which are also available in dt2 to dt3. also required to store not matching records in 4th dt4
I found this but does not know how to copy to datatable properly and also how not equals works here
var matchingRows = from s1 in dt1.AsEnumerable()
join s2 in d2.AsEnumerable() on s1.Field<int>("Id") equals s2.Field<int>("Id")
select s1;
I do not like using var when it is not necessary. You are loosing track of what you are actually doing. mathcingRows is a List. So the task is simple :
List<DataRow> matchingRows = (from s1 in dt1.AsEnumerable()
join s2 in dt2.AsEnumerable() on s1.Field<int>("Id") equals s2.Field<int>("Id")
select s1).ToList();
foreach (DataRow row in matchingRows)
{
dt4.Rows.Add(row);
}
You can create two queries to find the matching and non-matching rows and then copy the rows into each answer DataTable:
var dt3 = dt1.Clone();
var dt4 = dt1.Clone();
var matchingRows = from s1 in dt1.AsEnumerable()
join s2 in dt2.AsEnumerable() on s1.Field<int>("Id") equals s2.Field<int>("Id")
select s1;
matchingRows.CopyToDataTable(dt3, LoadOption.OverwriteChanges);
var nonMatchingRows = from s1 in dt1.AsEnumerable()
where !dt2.AsEnumerable().Any(s2 => s2.Field<int>("Id") == s1.Field<int>("Id"))
select s1;
nonMatchingRows.CopyToDataTable(dt4, LoadOption.OverwriteChanges);
If dt2 has a large number of entries and performance is more important than memory, you could convert dt2 to a HashSet to optimize the match testing:
var dt2hs = new HashSet<int>(dt2.AsEnumerable().Select(r => r.Field<int>("Id")));
var matchingRows = from s1 in dt1.AsEnumerable()
where dt2hs.Contains(s1.Field<int>("Id"))
select s1;
var nonMatchingRows = from s1 in dt1.AsEnumerable()
where !dt2hs.Contains(s1.Field<int>("Id"))
select s1;
Another performance option would be to just scan dt1 once and then manually loop and select each destination:
var dt1jdt2 = from s1 in dt1.AsEnumerable()
join s2 in dt2.AsEnumerable() on s1.Field<int>("Id") equals s2.Field<int>("Id") into s2j
from s2 in s2j.DefaultIfEmpty()
select new { s1, s2 };
foreach (var r in dt1jdt2) {
if (r.s2 != null)
dt3.Rows.Add(r.s1.ItemArray);
else
dt4.Rows.Add(r.s1.ItemArray);
}
Of course you can combine the HashSet and single scan options:
var dt2hs = new HashSet<int>(dt2.AsEnumerable().Select(r => r.Field<int>("Id")));
foreach (var s1 in dt1.AsEnumerable())
if (dt2hs.Contains(s1.Field<int>("Id")))
dt3.Rows.Add(s1.ItemArray);
else
dt4.Rows.Add(s1.ItemArray);

Delete using LINQ by joining two datatables

I have two datatable DurationByCurrency(inside a dataset) and Fund which looks like below
I want to delete the rows in Duration By Currency Datatable whose FundCode has value as 2 in Fund Dt by performing a join.
var result = from table1 in raptorDS.Tables[RaptorTable.DurationByCurrency].AsEnumerable()
join table2 in fundDT.AsEnumerable()
on table1.Field<string>("FundCode") equals table2.Field<string>("FundCode") into ps
from row in ps.DefaultIfEmpty()
{
//delete query
}
Please help me on this as I am new to LINQ.
var result = from row1 in raptorDS.Tables[RaptorTable.DurationByCurrency].AsEnumerable()
join row2 in fundDT.AsEnumerable()
on row1.Field<string>("FundCode") equals row2.Field<string>("FundCode")
where row1.Field<string>("value")
equals "2" select row1;
result.ToList().ForEach(row => row.Delete());
sample test code for linqpad:
void Main()
{
//sample data for test
DataSet ds = new DataSet();
ds.Tables.Add(GetTable1());
ds.Tables.Add(GetTable2());
var result = ( from rec1 in ds.Tables[0].AsEnumerable()
join rec2 in ds.Tables[1].AsEnumerable()
on rec1.Field<string>("FC") equals rec2.Field<string>("FC")
where rec2.Field<int>("Value") == 2 select rec1);
result.ToList().ForEach(row => row.Delete());
//now you have only "ABCD" and "AZY" in table 1
//ds.Tables[0].Dump(); linqpad display result
}
DataTable GetTable1()
{
DataTable table = new DataTable();
table.Columns.Add("FC", typeof(string));
table.Rows.Add("ABCD");
table.Rows.Add("XYZ");
table.Rows.Add("AZY");
return table;
}
DataTable GetTable2()
{
DataTable table = new DataTable();
table.Columns.Add("FC", typeof(string));
table.Columns.Add("Value", typeof(int));
table.Rows.Add("ABCD", 1);
table.Rows.Add("XYZ", 2);
table.Rows.Add("AZY",3);
return table;
}

How do I use SELECT GROUP BY in DataTable.Select(Expression)?

I try to remove the duplicate rows by select a first row from every group.
For Example
PK Col1 Col2
1 A B
2 A B
3 C C
4 C C
I want a return:
PK Col1 Col2
1 A B
3 C C
I tried following code but it didn't work:
DataTable dt = GetSampleDataTable(); //Get the table above.
dt = dt.Select("SELECT MIN(PK), Col1, Col2 GROUP BY Col1, Col2);
DataTable's Select method only supports simple filtering expressions like {field} = {value}. It does not support complex expressions, let alone SQL/Linq statements.
You can, however, use Linq extension methods to extract a collection of DataRows then create a new DataTable.
dt = dt.AsEnumerable()
.GroupBy(r => new {Col1 = r["Col1"], Col2 = r["Col2"]})
.Select(g => g.OrderBy(r => r["PK"]).First())
.CopyToDataTable();
dt = dt.AsEnumerable().GroupBy(r => r.Field<int>("ID")).Select(g => g.First()).CopyToDataTable();
dt.AsEnumerable()
.GroupBy(r => new { Col1 = r["Col1"], Col2 = r["Col2"] })
.Select(g =>
{
var row = dt.NewRow();
row["PK"] = g.Min(r => r.Field<int>("PK"));
row["Col1"] = g.Key.Col1;
row["Col2"] = g.Key.Col2;
return row;
})
.CopyToDataTable();
This solution sort by Col1 and group by Col2. Then extract value of Col2 and display it in a mbox.
var grouped = from DataRow dr in dt.Rows orderby dr["Col1"] group dr by dr["Col2"];
string x = "";
foreach (var k in grouped) x += (string)(k.ElementAt(0)["Col2"]) + Environment.NewLine;
MessageBox.Show(x);
Based on #Alfred Wallace's solution :
DataTable dt = new DataTable();
dt.Columns.Add("Col1");
dt.Columns.Add("Col2");
dt.Rows.Add("120", "34");
dt.Rows.Add("121", "34");
dt.Rows.Add("122", "34");
dt.Rows.Add("1", "345");
dt.Rows.Add("2", "345");
dt.Rows.Add("3", "345");
var grouped = from DataRow dr in dt.Rows orderby dr["Col1"] group dr by dr["Col2"];
string xxx = "", yyy = "";
foreach (var k_group in grouped)
{
xxx += (string)(k_group.ElementAt(0)["Col1"]) + Environment.NewLine;
foreach (DataRow item_dr in k_group)
{
yyy += (string)(item_dr["Col1"]) + Environment.NewLine;
// or use WhatEverMethod(item_dr);
}
var zzz = k_group.Max(g => g["Col1"]);
var qqq = k_group.Key;
}

How to populate DataTable with anonymous LINQ result

I have the following LINQ query:
var timesheets = from timesheet in entities.Timesheets
join timesheetTask in entities.Timesheet_Task on timesheet.Id equals timesheetTask.Timesheet_Id
join task in entities.Tasks on timesheetTask.Task_Id equals task.Id
join project in entities.Projects on task.Project_Id equals project.Id
join department in entities.Departments on project.Department_Id equals department.Id
where timesheet.Employee_Id == employeeId
select new
{
date = timesheet.Date,
taskName = task.Name,
projectName = project.Name,
projectDesc = project.Description,
departmentName = department.Name,
taskEstimatedHours = task.Estimated_Hours,
timesheetHours = timesheetTask.Hours
};
How can I put these results into a DataTable which I can then bind to a DataGridView control?
This is what I'm currently doing:
table.Columns.Add("date");
table.Columns.Add("taskName");
table.Columns.Add("projectName");
table.Columns.Add("projectDesc");
table.Columns.Add("departmentName");
table.Columns.Add("taskEstimatedHours");
table.Columns.Add("timesheetHours");
foreach (var item in timesheets)
{
table.Rows.Add(item.date, item.taskName, item.projectName,
item.projectDesc, item.departmentName, item.taskEstimatedHours,
item.timesheetHours);
}
}
Update: Here is my updated code:
DataTable table = new DataTable();
using (PTMS_DataEntities entities = new PTMS_DataEntities())
{
var timesheets = from timesheet in entities.Timesheets
join timesheetTask in entities.Timesheet_Task on timesheet.Id equals timesheetTask.Timesheet_Id
join task in entities.Tasks on timesheetTask.Task_Id equals task.Id
join project in entities.Projects on task.Project_Id equals project.Id
join department in entities.Departments on project.Department_Id equals department.Id
where timesheet.Employee_Id == employeeId
select new
{
date = timesheet.Date,
taskName = task.Name,
projectName = project.Name,
projectDesc = project.Description,
departmentName = department.Name,
taskEstimatedHours = task.Estimated_Hours,
timesheetHours = timesheetTask.Hours
};
table.Columns.Add("date", typeof(DateTime));
table.Columns.Add("taskName", typeof(string));
table.Columns.Add("projectName", typeof(string));
table.Columns.Add("projectDesc", typeof(string));
table.Columns.Add("departmentName", typeof(string));
table.Columns.Add("taskEstimatedHours", typeof(int));
table.Columns.Add("timesheetHours", typeof(int));
List<DataRow> list = new List<DataRow>();
foreach (var item in timesheets)
{
//table.Rows.Add(item.date, item.taskName, item.projectName,
// item.projectDesc, item.departmentName, item.taskEstimatedHours,
// item.timesheetHours);
var row = table.NewRow();
row.SetField<DateTime>("date", item.date);
row.SetField<string>("taskName", item.taskName);
row.SetField<string>("projectName", item.projectName);
row.SetField<string>("projectDesc", item.projectDesc);
row.SetField<string>("departmentName", item.departmentName);
row.SetField<int>("taskEstimatedHours", item.taskEstimatedHours);
row.SetField<int>("timesheetHours", item.timesheetHours);
list.Add(row);
}
table = list.CopyToDataTable();
}
Here is the SQL query I tested in SSMS (which should be the equivalent of the LINQ query):
SELECT dbo.Department.Name, dbo.Task.Name AS Expr1, dbo.Task.Estimated_Hours, dbo.Timesheet.Date, dbo.Project.Name AS Expr2, dbo.Project.Description,
dbo.Timesheet_Task.Date AS Expr3
FROM dbo.Department INNER JOIN
dbo.Project ON dbo.Department.Id = dbo.Project.Department_Id INNER JOIN
dbo.Task ON dbo.Project.Id = dbo.Task.Project_Id INNER JOIN
dbo.Timesheet_Task ON dbo.Task.Id = dbo.Timesheet_Task.Task_Id INNER JOIN
dbo.Timesheet ON dbo.Timesheet_Task.Timesheet_Id = dbo.Timesheet.Id
If you really want to populate DataTable:
// your query
var timesheets = ...
// design table first
DataTable table = new DataTable();
table.Columns.Add(new DataColumn
{
ColumnName = "TaskName",
DataType = typeof(String);
});
...
List<DataRow> list = new List<DataRow>();
foreach (var t in timesheets)
{
var row = table.NewRow();
row.SetField<string>("TaskName", t.taskName); // extension method from System.Data.DataSetExtensions.dll
...
list.Add(row);
}
DataTable table = list.CopyToDataTable(); // extension method too
Or more LINQ way:
timesheets
.Select(t =>
{
var row = table.NewRow();
...
return row;
})
.CopyToDataTable();
Or in same query syntax. Implement a method:
static DataRow NewRow(DataRow row, string taskName, ....)
{
...
}
Then query itself:
(from ...
where ...
select NewRow(table.NewRow(), task.Name, ...)
).CopyToDataTable();
Call .ToList().
The resulting List<T> can also be bound to a DataGridView, and is easier to work with than a DataTable.
I'm using FastMember for this purpose. It uses IL instead of reflection (much faster) to iterate over all of the property and field values automatically. Code sample from the site:
IEnumerable<SomeType> data = ...
var table = new DataTable();
using(var reader = ObjectReader.Create(data))
{
table.Load(reader);
}

merge 2 datatable

I have 2 Datatable dt and dt2
var dt = MultiCheckCombo3.GetAllChechedBox();
var dt2 =manager.GetAllStudents(student_id, classid);
In the first table dt are two columns "id_staff" and "name_staff"
In the second table are several columns but 2 of them repeat "id_staff" and "name_staff"
I want to create a new DataTable with the fields "id_staff" and "name_staff" common DataTable dt and dt2
how joined these tables?
dt3= dt+dt2
You can use Linq to join the two tables. See the following example.
Code from the article:
var innerGroupJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
select new { CategoryName = category.Name, Products = prodGroup };
Have a look at the DataTable.Merge method:
This link from Microsoft has an example of how to do this
If dt and dt2 are DataTables, you can use datatable merge.
DataTable dt3 = dt.Copy()
dt3.Merge(dt2, false, MissingSchemaAction.Ignore)
Maybe something like this:
var dt=new DataTable();
dt.Columns.Add("id_staff",typeof(int));
dt.Columns.Add("name_staff",typeof(string));
var dt2=new DataTable();
dt2.Columns.Add("id_staff",typeof(int));
dt2.Columns.Add("name_staff",typeof(string));
dt.Rows.Add(1,"test");
dt2.Rows.Add(2,"test2");
var result=
(
from datatable1 in dt.AsEnumerable()
select new
{
id_staff=datatable1.Field<int>("id_staff"),
name_staff=datatable1.Field<string>("name_staff")
}
).Concat
(
from datatable2 in dt2.AsEnumerable()
select new
{
id_staff=datatable2.Field<int>("id_staff"),
name_staff=datatable2.Field<string>("name_staff")
}
);

Categories

Resources