SELECT all columns in addition to some summary columns using LINQ - c#

Suppose there is a table with more than 20 columns: (col1, col2, ... )
If I want to display the sum of col1 and col2 as well as the other columns,
In SQL I could:
SELECT (col1+col2), * FROM table1;
But in LINQ, I have to
from tb in table1
select new
{
sum = tb.col1 + tb.col2,
col1 = tb.col1,
col2 = tb.col2,
...
};
Is there another simpler ways? Thanks.

You can extend type of tb entity by sum property and write something like:
table1
.Select(tb => new
{
Tb = tb,
Sum = tb.col1 + tb.col2
})
.Select(x =>
{
x.Tb.sum = x.Sum;
return x.Tb;
});

Related

LINQ Equivalent of "select *, count()"

I have two table A , B on SQL Server like bellow:
Columns of A: id1, id2, col_1, ... , col_100
Columns of B: id1, id2, ... (some columns)
I want to write the equivalent of below SQL query in the C# Linq:
select *, (select count(*) from B where A.id1 = B.id1 and A.id2 = b.id2) from A
I know that this can be done like below:
var lst = db.TableA.Select(a => new {
id1 = a.id1,
id2 = a.id2,
col_1 = a.col_1,
...
,
col_100 = a.col_100,
count = db.TableB.Where(b => b.id1 = a.id1 && b.id2 == a.id2).Count()
});
But in this format I have to mention all the columns of the table A, While I just want to add just one new column to the existing columns of the table A, Something like this: select *, count()
Can you help me?
How about this:
var result = dbContext.TableA.Select(a => new
{
A = a,
Count = dbContext.TableB.Where(b => b.id1 = a.id1 && b.id2 == a.id2)
.Count(),
});
So you select the complete row from tableA in property A, and you put the number of corresponding items in tableB in property Count

return 0 for items count in linq statement

Lets say I have the following EF6 Linq statement which counts number of items for 2 tables (Table1 has 10 items and Table2 has no items) :
var q = db.Table1.GroupBy(g => "Table1").Select(g => new { Name = g.Key, EntryCount = g.Count() })
.Union(db.Table2.GroupBy(g => "Table2").Select(g => new { Name = g.Key, EntryCount = g.Count() }));
var r = q.ToList();
The expected result should be something like
Name | EntryCount
---------------------
Table1 | 10
Table2 | 0
However because Table2 doesn't have any items it doesn't appear in the final result and I get the following:
Name | EntryCount
---------------------
Table1 | 10
How can I make sure Table 2 always appear in the final list even if its empty and doesn't have any records?
To give you a background on why I am doing this Linq statement , I am converting the following TSQL statement into a linq query:
CREATE FUNCTION [dbo].[ufnGetLookups] ()
RETURNS
#lookupsWithItemCounts TABLE
(
[Name] VARCHAR(100),
[EntryCount] INT
)
AS
BEGIN
INSERT INTO #lookupsWithItemCounts([Name],[EntryCount])
VALUES
('Table1', (SELECT COUNT(*) FROM Table1)),
('Table2', (SELECT COUNT(*) FROM Table2)),
('Table3', (SELECT COUNT(*) FROM Table3))
RETURN;
END
Also its very important to for this linq statement to run in one database trip, not multiple.
If you have a list of tables then table list can be used to union a row with EntryCount = 0 and then on final result set a GroupBy on Name and Sum of EntryCount will provide desired result.
//List of tables
var tableList = new string[] { "Table1", "Table2" };
var res = db.Table1
.GroupBy(t1 => "Table1")
.Select(gt1 => new { Name = gt1.Key, EntryCount = gt1.Count()})
.Union(db.Table2
.GroupBy(t2 => "Table2")
.Select(gt2 => new { Name = gt2.Key, EntryCount = gt2.Count()})
)
.Union(tableList
.GroupBy(s => s)
.Select(gs => new { Name = gs.Key, EntryCount = 0 })
)
.GroupBy(gg => gg.Name)
.Select(fg => new {Name = fg.Key, EntryCount=fg.Select(ee => ee.EntryCount).Sum()})
.ToList();
The result will have EntryCount for all tables in list.
You can do this by creating a default table with a single row in it.
var ans = Table1.GroupBy(u => "Table1")
.Select(ug => new { Name = ug.Key, EntryCount = ug.Count() })
.Union(Table2.GroupBy(l => "Table2")
.Select(lg => new { Name = lg.Key, EntryCount = lg.Count() })
.Union(OneRowTable.GroupBy(u2 => 1)
.Select(u2g => new { Name = "Table2", EntryCount = u2g.Count()-1 }) )
.OrderByDescending(cg => cg.EntryCount)
.Take(1)
);
This is evaluated in a single round trip to the database by LINQ to SQL. I can't easily test with LINQ to EF.
Note that in EF Core 3.0, the original query is translated in such a way as to return a 0 row for any empty tables.

Extract DataRow with specific column from a DataSet view in C#

I am want to get a specific row from a dataset, not the entire row but only specifics column from the row
it's should be something like that:
dataRow datarow1 = myDataSet.Tables["table1"].Column["column3
and column4"].Select(column1='1' and column2='specificvalue');
someone can help me?
Slightly different syntax:
var result = from row in set.Tables["table1"].AsEnumerable()
where row.Field<int>("column1") == 1 &&
row.Field<string>("column2") == "specificValue"
select new { Column3 = row.Field<string>("Column3"),
Column4 = row.Field<string>("Column4") };
My best guess:
var datarows = myDataSet.Tables["table1"].AsEnumerable()
.Where(x=> x.Field<int>("col1") == 1 && x.Field<string>("col2") == "specificvalue")
.Select(x=>new
{
col3 = x.Field<int>("col3"),
col4 = x.Field<int>("col4")
})
.ToList();

How to concat a column value based on id

I have a table like this in C# from a dataset
COL1 COL2 COL3 COL4 COL5
1000 APPLE 50 92 TESTING
1000 APPLE 50 92 ALPHA
1000 APPLE 50 92 BETA
1000 APPLE 50 92 OMEGA
2000 ORANGE 60 90 DELTA
2000 ORANGE 60 90 TEST
2000 ORANGE 60 90 SLEEP
I need result like this
COL1 COL2 COL3 COL4 COL5
1000 APPLE 50 92 TESTINGAPHABETAOMEGA
2000 ORANGE 60 90 DELTASLEEPTEST
How to achieve this ?
I strucked after this line
var result = from row in dataTable.AsEnumerable()
group row by row.Field<int>("COL1") into grp
select new
{
COL1= grp.Key,
Count = grp.Count()
};
I dont think you can do that with LINQ, but heres a little subroutine that will work for you.
var _rowlist = table.AsEnumerable().OrderBy(x => x.Field<Int32>("COL1")).ThenBy(x => x.Field<string>("COL2")).ThenBy(x => x.Field<string>("COL3")).ThenBy(x => x.Field<string>("COL4")).ToList();
DataTable _newtable = table.Clone();
string oldrowid = "";
foreach (DataRow _indrow in _rowlist)
{
if (!oldrowid.Equals(_indrow["COL1"].ToString()))
{
oldrowid = _indrow["COL1"].ToString();
DataRow _newrow = _newtable.NewRow();
_newrow["COL1"] = _indrow["COL1"].ToString();
_newrow["COL2"] = _indrow["COL2"].ToString();
_newrow["COL3"] = _indrow["COL3"].ToString();
_newrow["COL4"] = _indrow["COL4"].ToString();
_newrow["COL5"] = _indrow["COL5"].ToString();
_newtable.Rows.Add(_newrow);
}
else
{
Int32 _id = Int32.Parse(_indrow["COL1"].ToString());
DataRow _row = _newtable.AsEnumerable().Where(a => a.Field<Int32>("COL1") == _id).SingleOrDefault();
int Index = _newtable.Rows.IndexOf(_row);
_row["COL5"] += "," + _indrow["COL5"].ToString();
}
}
//_newtable contains what you want
Try this:
var result =
from row in dataTable.AsEnumerable()
let COL1 = row.Field<int>("COL1")
let COL2 = row.Field<string>("COL2")
let COL3 = row.Field<int>("COL3")
let COL4 = row.Field<int>("COL4")
let COL5 = row.Field<string>("COL5")
group COL5 by new { COL1, COL2, COL3, COL4, } into grp
select new
{
COL1 = grp.Key.COL1,
COL2 = grp.Key.COL2,
COL3 = grp.Key.COL3,
COL4 = grp.Key.COL4,
COL5 = String.Join("", grp),
};
var result = from row in dt.AsEnumerable()
group row by row.Field<int>("COL1") into grp
let firstCols = grp.First()
let lastCells = string.Join("", grp.Select(x => x[4]).ToArray())
select new object[] { firstCols[0], firstCols[1], firstCols[2], firstCols[3], lastCells };
var dtResult = dt.Clone();
foreach (var item in result )
{
dtResult.Rows.Add(item);
}

DataTable Linq join many columns

I have a trouble with Linq Join. I want to join 2 tables, which they have same structure with n-columns. My problem is i don't know the names of those columns, so how can i rewrite those in select new?
Table 1: Here I have some parameters in ID, Name and LastName. Comment, Attribute and the rest are null
ID Name LastName Comment Attribute ...
"what" "ABC" ...
"hello" "SDE" ...
3 lola
1 de
4 miki
... ... ... ...
Table 2: Here is the same like Table 1 but it has some parameters in Comment, Attribute and the Rest.
ID Name LastName Comment Attribute ...
"what" "ABC" ...
"hello" "SDE" ...
1 de "hi"
4 miki "OKK"
3 lola "yo" "LL"
Result: I would like to have joined Table like this
ID Name LastName Comment Attribute ...
"what" "ABC" ...
"hello" "SDE" ...
3 lola "yo" "LL"
1 de "hi"
4 miki "OKK"
... ... ... ... ... ...
My Code would be:
var Result= from tb1 in table1.AsEnumerable()
join tb2 in tabl2.AsEnumerable()
on new
{
Name = tb1.Field<String>("Name"),
LastName = tb1.Field<String>("LastName"),
} equals new
{
Name=tb2.Field<String>("Name"),
LastName=tb2.Field<String>("LastName"),
}
into grp1
from tb3 in grp1.DefaultIfEmpty()
select new
{
ID = tb1.Field<String>("ID"),
Name = tb1.Field<String>("Name") ,
LastName = tb1.Field<String>("LastName"),
Comment = tb3!= null ? tb3.Field<String>("Comment") : null,
Attribute= tb3!= null ? tb3.Field<String>("Attribute") : null,
...
// Here should be next Columns Name but don't know how to put there
};
I tried with this code but my compiler just hanged out, dont know why
for (int i = 2; i < table1.Rows.Count; i++)
{
foreach (DataRow dr in table2.Rows)
{
if ((table1.Rows[i]["Name"].ToString() == dr["Name"].ToString())&&table1.Rows[i]["LastName"].ToString() == dr["LastName"].ToString())
{
table1.Rows.RemoveAt(i);
table1.ImportRow(dr);
}
}
}
dataGridView1.DataSource = table1;
For each row1 in table1, if there is a matching row2 in table2, use row2. Otherwise, use row1.
var newTable = table1.Clone();
foreach (DataRow row1 in table1.Rows) // To skip the first 2, use table1.Rows.Cast<DataRow>().Skip(2)
{
var row = table2.Rows.Cast<DataRow>().FirstOrDefault(row2 =>
row1["Name"].ToString() == row2["Name"].ToString() &&
row1["LastName"].ToString() == row2["LastName"].ToString()) ?? row1;
newTable.ImportRow(row);
}
dataGridView1.DataSource = newTable;
How about joining as you did and then copying the three known fields from table1's rows to table2's rows?
var copiedTable2 = table2.Copy(); // Copy table2 if you don't want it to be modified
var items = from tb1 in table1.AsEnumerable()
join tb2 in copiedTable2.AsEnumerable()
on new
{
Name = tb1.Field<String>("Name"),
LastName = tb1.Field<String>("LastName"),
} equals new
{
Name=tb2.Field<String>("Name"),
LastName=tb2.Field<String>("LastName"),
}
into grp1
from tb3 in grp1.DefaultIfEmpty()
select new
{
ID = tb1.Field<String>("ID"),
Name = tb1.Field<String>("Name") ,
LastName = tb1.Field<String>("LastName"),
Row = tb3 ?? table2.NewRow();
};
foreach(var item in items)
{
item.Row.SetField<String>("ID", item.ID);
item.Row.SetField<String>("Name", item.Name);
item.Row.SetField<String>("LastName", item.LastName);
}
var rows = items.Select(x => x.Row);
// How to set the rows as a DataGridView's DataSource
var result = table2.Clone();
foreach(var row in rows)
{
result.Rows.Add(row.ItemArray);
}
dataGridView.DataSource = result;
Try this, no need of using loops
var resultTable = from tb1 in table1.AsEnumerable()
join tb2 in tabl2.AsEnumerable()
on tb1["Name"].ToString() equals tb2["Name"].ToString()
where tb1["LastName"].ToString() == tb2["LastName"].ToString()
select r;
DataTable resultTable =result.CopyToDataTable();

Categories