Datatable search by LINQ to avoid duplication - c#

I have a column in dataTable with blank rows
Column1
A
B
C
D
E
I need to set if exist and to avoid adding, but blank rows should not be counted. Only rows with data should be in the (if exists). Thanks
bool exists = dt.Select().ToList().Exists(row => row["column1"].ToString() == txtbox)
if(exists == true)
{}
else
// it includes blank so it goes to true, which I need is blank rows should not be included.

var lignesNonContainEmptyString = dt.Select()
.Where(row => row["column1"] != null
&& row["column1"].ToString() == txtbox
&& !string.IsNullOrEmpty(row["column1"].ToString()))
bool exists = lignes.Count() != 0;
OR
bool exists = dt.Select()
.Any(row => row["column1"] != null
&& row["column1"].ToString() == txtbox
&& !string.IsNullOrEmpty(row["column1"].ToString()))

You would like to return false if the textbox is empty, so add the condition for the textbox.
bool exists = !string.IsNullOrWhiteSpace(txtbox)
&& dt.Select().ToList()
.Exists(row => row["column1"].ToString() == txtbox)
By the way, instead of using .Select().ToList(), you can add a reference to System.Data.DataTableExtensions and use the Extension AsEnumerable:
dt.AsEnumerable().Any( .....

How about this: non linq way
bool DataTableNonEmptyCount()
{
int count =0;
foreach (DataColumn col in row.Table.Columns)
if (!row.IsNull(col))
count ++;
return count;
}
This will return a count of all non null row in column.

Based on Thierry's answer, you can also use the Any(predicate) syntax:
var existsLineWithoutEmptyString =
dt.AsEnumerable()
.Any(row => row["column1"] != null
&& row["column1"].ToString() == txtbox
&& !string.IsNullOrEmpty(row["column1"].ToString()))

this code can help you
from a in list where ( Column1 != null || Column1 != "")
&& Column1 == searchfield
select a

Related

Converting a given SQL Query to LINQ

I'm new to creating a LINQ so I'm having a hard time converting this SQL query into LINQ. Can someone help me please
SELECT *
FROM myTable1
WHERE (Flag1 <> 'X' OR Flag2 != 'X' OR Flag3 != 'X')
AND number IN (SELECT externalid FROM db2.myTable2 WHERE item = 6)
This is what I've already tried
//get external id
var externalNumber = from s in db2.myTable2
where s.item == 6
select externalid;
var query = from f in db1.myTable1
where (f.Flag1 != "X" || f.Flag2 != "X" || f.Flag3 != "X") && f.number == externalNumber
select f;
Direct translation is:
var query =
from f in db.myTable1
where (f.Flag1 != "X" || f.Flag2 != "X" || f.Flag3 !="X") &&
db.myTable2.Where(s => s.item == 6).Select(s => s.externalId).Contains(f.number)
select f;
IN in LINQ has analogue Contains
var externalid = db2.myTable2Repository.FirstOrDefault(f=>f.item == 2).Result.externalid;
This first code return externalid from db2.myTable2
var data = myTable1Repository.GetAll().Where(w=>(w.Flag1 != X || w.Flag2 != X || w.Flag3 != X) && w.number == externalid)
Second code:
GetAll() is a method of your repository (or baseRepository) and Where() is part of linq
First part of where -> (w.Flag1 != X || w.Flag2 != X || w.Flag3 != X) is self explain
Second part -> (&& w.number == externalid):
I'm not very good with sql so this second part may have got it wrong ,but if I understand correctly, you check the "number" property against a value from another table, so you can just look up this value and store it in a variable.
I'm sorry if I misunderstood the second part in the "and number in", I'm really not good at SQL, and for my bad English too.
If you have any questions we are here :D
Try the Below code:
DatabaseEntities dc=new DatabaseEntities();
var res=dc.myTable1.Where(s=>s.Flag <> 'X' || Flag2 !='X' || Flag3 !='X' && s.number.Contains(dc.myTable2.Where(m=>m.item==6)))

How do I set specific columns in a DataGridView to 0 if it is blank?

In this example I am looping through each cell individually.
However, I have a name column and another optional column which I want to avoid. So I'd rather want to loop through a specific set of columns without the optional one instead but I'm not sure how.
This is how I did the thorough sweep:
foreach (DataGridViewRow row in DGVExcel.Rows)
{
for (int i = 0; i < row.Cells.Count; i++)
{
if (row.Cells[i].Value == null || row.Cells[i].Value == DBNull.Value ||
String.IsNullOrWhiteSpace(row.Cells[i].Value.ToString()))
{
row.Cells[i].Value = 0;
//DGVExcel.RefreshEdit();
}
}
}
However, I have a name column [...] so I'd rather'd loop through specific columns instead
If I understand you correctly you could get the index of the column and you can skip one for-loop:
int colindex = DGVExcel.Columns["SpecificColumnName"].Index;
foreach (var row in DGVExcel.Rows)
{
if (row.Cells[colindex].Value == null || row.Cells[colindex].Value == DBNull.Value ||
String.IsNullOrWhiteSpace(row.Cells[colindex].Value.ToString()))
{
row.Cells[colindex].Value = 0;
//DGVExcel.RefreshEdit();
}
}
EDIT
Is there a way to list the excluded columns instead of the included ones, because listing each one would be messy
In this case I would leave it with 2 for-loops. Basically you could save all the names in a List and check whether it contains the name of the current column and if it doesn't then you can do your 0 replacement.
List<string> ExcludedColumnsList = new List<string> { "ExcludedColumnName_1", "ExcludedColumnName_2" };
foreach (DataGridViewRow row in DGVExcel.Rows)
{
for (int i = 0; i < row.Cells.Count; i++)
{
if (!ExcludedColumnsList.Contains(DGVExcel.Columns[i].Name))
{
if (row.Cells[i].Value == null || row.Cells[i].Value == DBNull.Value ||
String.IsNullOrWhiteSpace(row.Cells[i].Value.ToString()))
{
row.Cells[i].Value = 0;
//DGVExcel.RefreshEdit();
}
}
}
}
Another option could also be to use linq. Get all indices except the excluded columns and foreach only through those:
List<string> ExcludedColumnsList = new List<string> { "ExcludedColumnName_1", "ExcludedColumnName_2" };
List<int> indexList = dataGridView1.Columns.Cast<DataGridViewColumn>()
.Where(x => !ExcludedColumnsList.Contains(x.Name))
.Select(x => x.Index).ToList();
foreach (DataGridViewRow row in DGVExcel.Rows)
{
foreach (int i in indexList)
{
if (row.Cells[i].Value == null || row.Cells[i].Value == DBNull.Value ||
String.IsNullOrWhiteSpace(row.Cells[i].Value.ToString()))
{
row.Cells[i].Value = 0;
//DGVExcel.RefreshEdit();
}
}
}

Setting a datatable cell value using LINQ according to some conditions

I am trying to set a true boolean value to a cell in datatable according to some conditions using LINQ.
foreach (DataRow dr in dtLeftResult.Rows)
{
var shipNo = dr[0].ToString();
var invoiceNo = dr[1].ToString();
var res = dtInvoicesList.Rows
.Cast<DataRow>()
.Where(r => r.Field<string>("[Shipment#]") == shipNo && r.Field<string>("[Invoice#]") == invoiceNo)
.Select(r => r.Field<string>("IsValid")).First();
}
I need to set the IsValid field (boolean) to true after finding the correcet row in the datatable. I am finding the row but I am not able to set the value.
How can I do it?
In your res variable is the value of IsValid because of your call to Select(...)
What you want to do is get the row:
var row = dtInvoicesList.Rows
.Cast<DataRow>()
.Where(r => r.Field<string>("[Shipment#]") == shipNo
&& r.Field<string>("[Invoice#]") == invoiceNo)
.First();
And set its value: row["IsValid"] = true;
Select statement in your query returns the value of a cell, what you want is the DataRow of the DataTable.
Modify your query to get filtered rows and then access the DataRow columns using columnname or Index.
var firstMatch = dtInvoicesList.Rows
.AsEnumerable()Where(r => r.Field<string>("[Shipment#]") == shipNo && r.Field<string>("[Invoice#]") == invoiceNo)
.FirstOrDefault();
if(firstMatch!= null)
{
firstMatch["IsValid"] = true; //new value.
}

Extract the sum of two things from datatable

I have a table in a SQL Server database with many columns but the important columns are LoggedState and InteractionType.
I need to find the number of break agents and the number of idle agents.
What I have tried
SqlCommand GraphCmd = new SqlCommand("getAgentStatues", Graphsqlcon);
SqlParameter tdate = new SqlParameter();
GraphCmd.CommandType = CommandType.StoredProcedure; ;
SqlDataAdapter DAGraph = new SqlDataAdapter(GraphCmd);
DataSet DSGraph = new DataSet();
DSGraph.Clear();
DAGraph.Fill(DSGraph);
DataTable DTgraph = new DataTable();
DTgraph = DSGraph.Tables[0];
int numberOfBreakAgents = 0;
int numberOfIdelAgents = 0;
foreach (DataRow row in DTgraph.Rows)
{
String LoggedState = row["LoggedState"].ToString().Trim().ToLower();
String InteractionType = row["InteractionType"].ToString();
if (LoggedState == "break")
{
numberOfBreakAgents++;
}
else if ((LoggedState == "activo") && (row["InteractionType"] == DBNull.Value))
{
numberOfIdelAgents++;
}
}
it works perfectly, but I am asking if there is a way (like grouping) to avoid the foreach statement
You could use the Group function from Linq:
var loggedStateGroups = dt.AsEnumerable().GroupBy(d => d["LoggedState"].ToString(), (group, row) => new
{
LoggedState = group,
AllCount = row.Count(),
NullCount = row.Where(r => r["InteractionType"] == DBNull.Value).Count()
});
That will group by the LoggedState with a count for each matching row (AllCount) and a count for rows where the InteractionType is DBNull.Value (NullCount).
We can then select the counts we are after by doing:
int numberOfBreakAgents = loggedStateGroups.Where(y => y.LoggedState == "break").First().AllCount;
int numberOfIdelAgents = loggedStateGroups.Where(y => y.LoggedState == "activo").First().NullCount;
Note I'm only using First assuming you will always have results. If you won't always have results you should use FirstOrDefault and perform a null check.
You could filter before using the Group by adding the following Where depending on your data.
.Where(r => r["LoggedState"].ToString() == "break" || r["LoggedState"].ToString() == "activo")
I've tested this with the following setup:
DataTable dt = new DataTable();
dt.Columns.Add("LoggedState");
dt.Columns.Add("InteractionType");
dt.Rows.Add("break", "inter1");
dt.Rows.Add("activo", DBNull.Value);
dt.Rows.Add("break", "inter1");
dt.Rows.Add("break", "inter2");
dt.Rows.Add("activo", "inter2");
And I get 3 and 1 for the numberOfBreakAgents and numberOfIdelAgents respectively.
Edit for using FirstOrDefault:
If you'd like to perform the null check as mentioned above you can replace the two int declaration lines above with:
var breakAgents = loggedStateGroups.Where(y => y.LoggedState == "break").FirstOrDefault();
var idelAgents = loggedStateGroups.Where(y => y.LoggedState == "activo").FirstOrDefault();
int numberOfBreakAgents = breakAgents != null ? breakAgents.AllCount : 0;
int numberOfIdelAgents = idelAgents != null ? idelAgents.NullCount : 0;
This is taking the first group that has the LoggedState of "break" or null if there isn't one. It then assigns numberOfBreakAgents the AllCount property if the group is not null or 0 if it is.
A similar thing is done for numberOfIdelAgents except we filter for the "activo" group and use the NullCount property as we aren't interested in all rows we are only interested in those where the InteractionType was DBNull.Value which we've captured in the NullCount property.
The null check is necessary if the result set will ever contain zero rows with the LoggedState of "activo" or zero rows with the LoggedState of "break". In that instance the .First() will return null and accessing AllCount or NullCount from that will result in a "Sequence contains no elements" exception.
Using the following DataTable definition will highlight the difference as it causes an exception for numberOfBreakAgents using First() but correctly returns 0 when using FirstOrDefault.
DataTable dt = new DataTable();
dt.Columns.Add("LoggedState");
dt.Columns.Add("InteractionType");
dt.Rows.Add("activo", "inter1");
dt.Rows.Add("activo", DBNull.Value);
dt.Rows.Add("activo", "inter1");
dt.Rows.Add("activo", "inter2");
dt.Rows.Add("activo", "inter2");
Could you not do
var breakAgents = from row in DTgraph.AsEnumerable()
where row["LoggedState"].ToString().Trim().ToLower() == "break"
select row;
var breakAgentsCount = breakAgents.Count();
and
var idleAgents = from row in DTgraph.AsEnumerable()
where row["LoggedState"].ToString().Trim().ToLower() == "activo"
&& row["InteractionType"] == DBNull.Value
select row;
var idleAgentsCount = idleAgents.Count();
Using the Count-function that LINQ provides us, the following solution should work:
// Cast the rows to a collection of DataRows.
IEnumerable<DataRow> collection = DTgraph.Rows.Cast<DataRow>();
// Get the number of Break Agents.
int numberOfBreakAgents = collection.Count(row => row["LoggedState"].ToString().Trim().ToLower() == "break");
// Get the number of Idel Agents.
int numberOfIdelAgents = collection.Count(row => row["LoggedState"].ToString().Trim().ToLower() == "activo" && row["InteractionType"] == DBNull.Value);
The cast is used to allow the use of LINQ on the DataRow-collection.
Another option would be to cast the DataRow-collection to a List of type DataRow. Then using a ForEach (also LINQ), to determine the agent-type:
List<DataRow> collection = DTgraph.Rows.Cast<DataRow>().ToList();
collection.ForEach(row =>
{
if (row["LoggedState"].ToString().Trim().ToLower() == "break")
numberOfBreakAgents++;
else if (row["LoggedState"].ToString().Trim().ToLower() == "activo" && row["InteractionType"] == DBNull.Value)
numberOfIdelAgents++;
});
Above example is very much the same to your example, but written a bit shorter and without the use of two strings (LoggedState and InteractionType).
You can execute sql query like this:
select
sum(case when LoggedState = "break" then 1 else 0 end) break_count,
sum(case when LoggedState = "activo" and InteractionType is null then 1 else 0 end) active_count
from table_name

How to verify row existence and delete it from DataTable using Linq or Select command?

Maybe I must use sometning like this:
var rows = ds.Tables["points"].Select("pupil_id == tempPupilId, discipline_id == intSelectedDisciplineId, point == Convert.ToInt32(currValue), point_date == dayToInsert");
foreach (var row in rows)
{
row.Delete();
}
But how check that this row is exists in Database?
You can try this:
var rowsToDelete = (from row in ds.Tables["Points"].AsEnumerable()
where row.Field<type>("pupil_id") == tempPupilId //(i guess that you have it on code side, if not compare it in the same awy)
&& row.Field<type>("discipline_id") == intSelectedDisciplineId && etc..
select row).ToList();
foreach (var r in rowsToDelete)
r.Delete();

Categories