Working with a ListBox from an SQL database - c#

I'm new to CS. I have a ListBox control that I populate from an SQL table called Category. I have a class called Category to match the fields from the DB. I want all my fields available to edit and save. The ListBox has a single field, CategoryDesc. When I select an item in the ListBox I want two textboxes and a check box to update with the CategoryID (string), CategoryDesc (string), and IsActive (bool). I have it working but it seems cumbersome and like I'm taking a lot of steps. I want to learn efficient coding so I'm submitting the following for suggestions on how to clean it up and make it more efficient. Any positive comments will be greatly appreciated.
id ListControl()
{
this.LstCategory.SelectedIndexChanged -= new System.EventHandler(this.LstCategory_SelectedIndexChanged);
DataTable categoryDt = new DataTable();
categoryDt = GetDataTable("GetListCategory");
for (int i = 0; i < categoryDt.Rows.Count; i++)
{
category.Add(new Category()
{
CategoryID = (int)(categoryDt.Rows[i]["CategoryId"]),
CategoryDesc = (string)(categoryDt.Rows[i]["CategoryDesc"]),
ShortCode = (string)(categoryDt.Rows[i]["ShortCode"]),
IsActive = (bool)(categoryDt.Rows[i]["IsActive"]),
CanDelete = (bool)(categoryDt.Rows[i]["CanDelete"])
});
LstCategory.Items.Add((string)(categoryDt.Rows[i]["CategoryDesc"]));
}
this.LstCategory.SelectedIndexChanged += new System.EventHandler(this.LstCategory_SelectedIndexChanged);
}
private void LstCategory_SelectedIndexChanged(object sender, EventArgs e)
{
if (LstCategory.SelectedIndex >= 0)
{
string desc = LstCategory.SelectedItem.ToString();
foreach (var c in category)
{
if (c.CategoryDesc == desc)
{
TxtDescription.Text = c.CategoryDesc;
TxtShortCode.Text = c.ShortCode;
ChkIsActive.Checked = c.IsActive;
}
}
}
else
{
TxtDescription.Text = string.Empty;
TxtShortCode.Text = string.Empty;
ChkIsActive.Checked = false;
}
}
Thanks.

Learn to use Linq
This
categoryDt = GetDataTable("GetListCategory");
for (int i = 0; i < categoryDt.Rows.Count; i++)
{
category.Add(new Category()
{
CategoryID = (int)(categoryDt.Rows[i]["CategoryId"]),
CategoryDesc = (string)(categoryDt.Rows[i]["CategoryDesc"]),
ShortCode = (string)(categoryDt.Rows[i]["ShortCode"]),
IsActive = (bool)(categoryDt.Rows[i]["IsActive"]),
CanDelete = (bool)(categoryDt.Rows[i]["CanDelete"])
});
LstCategory.Items.Add((string)(categoryDt.Rows[i]["CategoryDesc"]));
}
can be replaced by
category = categoryDt.Select(cd => new Category{
CategoryID = (int)(cd["CategoryId"]),
CategoryDesc = (string)(cd[i]["CategoryDesc"]),
ShortCode = (string)(cd["ShortCode"]),
IsActive = (bool)(cd[i]["IsActive"]),
CanDelete = (bool)(cd[i]["CanDelete"])}).ToList();
LstCategory.Items.AddRange(category.Select(c=>c.Desc));
and
string desc = LstCategory.SelectedItem.ToString();
foreach (var c in category)
{
if (c.CategoryDesc == desc)
{
TxtDescription.Text = c.CategoryDesc;
TxtShortCode.Text = c.ShortCode;
ChkIsActive.Checked = c.IsActive;
}
}
can be replaced by
var c = category.FirstOrDefault(c=>c ==desc);
TxtDescription.Text = c.CategoryDesc;
TxtShortCode.Text = c.ShortCode;
ChkIsActive.Checked = c.IsActive;
There might be a few typos here and there becuase I dont have yur data structures to try it out on.
But LINQ is incredibly useful for performing operations on collections.
'select' is used to transform 'project' (its not a filter)
'where' is used to filter
'FindFirstOrDefault' will retunr the first match (or null)
'Count' counts
'ToList' converts to list
The nice thing is you can chain then together
mylist.Where(...).Select(..) etc

Related

Xamarin forms stacklayout returning null

I tried to get the item on stacklayout into an SQLite Database, but it just won't carry any data with.
private void MainCategory_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var carier = e.SelectedItem as Item;
var cart_Itemsx = new List<cart_Items>();
cart_Itemsx.Add(new Models.cart_Items { cartid = 1, Id = carier.itid, image = carier.image, name = carier.title, price = carier.price1, quantity = "1", type = "Wash and Iron" });
cart_Itemsx.Add(new Models.cart_Items { cartid = 2, Id = carier.itid, image = carier.image, name = carier.title, price = carier.price2, quantity = "1", type = "Iron Only" });
SubCategory.ItemsSource = cart_Itemsx.ToList();
}
private void SubCategory_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var dbcontet = e.SelectedItem as cart_Items;
_dbPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "WashPro.db3");
var db = new SQLiteConnection(_dbPath);
db.CreateTable<cart_Items>();
var MaximumPrimaryKey = db.Table<cart_Items>().OrderByDescending(zt => zt.cartid).FirstOrDefault();
var waltani = new cart_Items()
{
cartid = (MaximumPrimaryKey == null ? 1 : MaximumPrimaryKey.cartid + 1),
Id = dbcontet.Id,
image = dbcontet.image,
name = dbcontet.name,
price = dbcontet.price,
quantity = dbcontet.quantity,
type = dbcontet.quantity
};
if (MaximumPrimaryKey == null)
{
db.Insert(waltani);
}
else if (MaximumPrimaryKey != null)
{
var MaximumQuantityKey = db.Table<cart_Items>().Where(m => m.cartid.Equals(dbcontet.cartid) && m.type.Equals(dbcontet.type)).FirstOrDefault();
if (MaximumQuantityKey != null)
{
waltani.price = dbcontet.price = 1;
db.Update(waltani);
}
}
SubCategory.SelectedItem = null;
}
image of the null error I got
I cannot even begin to understand the problem. The way I found around the problem will make my already dirty code way dirtier.
I have the damaging method I tried was using the selected context of the main stack panel to influence the second stack pannel.
I have even made the primary key of the cart_item model null.
Your selected element is null or database table does not contain any elements you are looking for in query, which is more likely because you are trying to initialize your database on SubCategory_ItemSelected. This is wrong approach.
Try to check if database item exist first.
var exist = db.Table<cart_Items>().OrderByDescending(zt => zt.cartid).Any();
if (exist)
{
var MaximumPrimaryKey = db.Table<cart_Items>().OrderByDescending(zt => zt.cartid).FirstOrDefault();
var waltani = new cart_Items()
{
cartid = (MaximumPrimaryKey == null ? 1 : MaximumPrimaryKey.cartid + 1),
Id = dbcontet.Id,
image = dbcontet.image,
name = dbcontet.name,
price = dbcontet.price,
quantity = dbcontet.quantity,
type = dbcontet.quantity
};
}
The problem lies at the last line of code.
SubListview.SelectedItem = null;
This somehow makes the casting not see the e.selected items.

How to Check or Uncheck a Checkbox in Datagridview based on existing data record from Table

I need help on part of this code. I'm using a checkbox column in my DataGridView control. When I retrieve my data record, if a value exists then the checkbox should be checked, and if not it should remain unchecked. How to I accomplish that on a DataGridView with this kind of logic?
using (DataContext dtContext = new DataContext())
{
var query = (from i in dtContext.materialTBheader where i.proj == Proj_id select i);
foreach (var r in query)
{
if (!string.IsNullOrEmpty(r.materialheader_id.ToString()))
{
string[] row = { r.materialheader_id.ToString(), r.materialname, r.description, string.Format("{0:n2}", r.totalAmount), GetCount(r.materialname, txtMainProjectHeader_id, Convert.ToDecimal(r.totalAmount)), "", -- cell checkbox if record exist true checked if not false uncheck };
dGVMaterialHeaderList.Rows.Add(row);
}
}
}
It dosen't need to add your rows by foreach, use DataSource Property
Suppose you have a List of Person and you want to show in dataGridview, you have to option
1)add your column to data grid in visual studio properties window
2)add your column with coding
then map your data to grid
here is an simple example to help yo
public class Person
{
public int Id { get; set; }
public string LastName { get; set; }
public bool Married { get; set; }
}
private void Form1_Load(object sender, EventArgs e)
{
//your data from ef
var myData = new List<Person>
{
new Person{Id=1,LastName="A1",Married =true},
new Person{Id=1,LastName="A2",Married =false},
new Person{Id=1,LastName="A3",Married =true},
};
//your columns
var idColumn = new System.Windows.Forms.DataGridViewTextBoxColumn
{
Name = "Id",
HeaderText = "Id",
DataPropertyName = "Id"
};
var lastNameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn
{
Name = "LastName",
HeaderText = "LastName",
DataPropertyName = "LastName"
};
var marriedColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn
{
Name="Married",
HeaderText="Married",
DataPropertyName= "Married"
};
// add your columns to grid
dGVMaterialHeaderList.Columns.Add(idColumn);
dGVMaterialHeaderList.Columns.Add(lastNameColumn);
dGVMaterialHeaderList.Columns.Add(marriedColumn);
dGVMaterialHeaderList.AutoGenerateColumns = false;
//bind your data
dGVMaterialHeaderList.DataSource = myData;
}
In your case the answer is something like below:
using (DataContext dtContext = new DataContext())
{
var query = (from i in dtContext.materialTBheader where i.proj == Proj_id select i).ToList();
var gridData = query.Select(r=>new
{
materialheader_id = r.materialheader_id.ToString(),
r.materialname,
r.description,
totalAmount = string.Format("{0:n2}", r.totalAmount),
Count = GetCount(r.materialname, txtMainProjectHeader_id, Convert.ToDecimal(r.totalAmount)),
isExist = !string.IsNullOrEmpty(r.materialheader_id.ToString())?true:false
}).ToList();
dGVMaterialHeaderList.DataSource = gridData;
}
I don't know your data structure but I know this is not best approach you choose
I hope this can help you

How to create a list from a CSV file in c#?

Simply put I have an excel CSV file with a table of Products and a Product Class in my project
I can't seem to extract the data in order to create a list of Product objects from the list in the CSV file.
I realise there is similar questions posted but I cannot seem to get it working correctly.
Can anyone identify the problem ?
private static List<Product> ReadProductFile()
{
List<Product> products = new List<Product>();
string curdir = Directory.GetCurrentDirectory();
string filename = #"C:\Projects\ProductSales\ProductSales\Data\productdetails.csv";
string[] linesInFile = File.ReadAllLines(filename);
string[] ProductDetails = new string[0];
for (int i = 0; i < linesInFile.Length; i++)
{
string currentLine1 = linesInFile[i];
ProductDetails = currentLine1.Split(',');
}
foreach (var p in ProductDetails)
{
Product prod = new Product()
{
prod.ID = p. ??
};
products.Add(prod);
}
}
Change your code to this:
for (int i = 0; i < linesInFile.Length; i++)
{
string currentLine1 = linesInFile[i];
ProductDetails = currentLine1.Split(',');
foreach (var p in ProductDetails)
{
Product prod = new Product();
{
prod.ID = p;
};
products.Add(prod);
}
}
Your ProductDetails now is just a number of string values, you need to associate these strings with specific fields. The easiest way is to do it manually, just check the order in the file and do something like:
for (int i = 1; i < linesInFile.Length; i++)
{
string currentLine1 = linesInFile[i];
ProductDetails = currentLine1.Split(',');
Product prod = new Product();
{
ID = ProductDetails[0];
Name = ProductDetails[1];
};
products.Add(prod);
}
I started the loop with i = 1 because I suppose that the first line will contain captions.
However, if the file format changes, you will have to rewrite this code, so you might want to link properties to columns automatically. If this is the case, have look at System.Reflection library.

C# Observable Collection LDAP Paths Children for WPF TreeView

I'm hoping someone can help. A long time windows forms/aspx user, moving to WPF.
Not expecting a coded answer to this, but any pointers on a different way to approach would be greatly appreciated - I am probably approaching this in a very backward way.
So the objective is to have an ObservableCollection with sub ObservableCollection "childen" within to then bind to my WPF treeview control.
I can bind my collection to the treeview without issues, and have styled it with checkboxes images as desired, frustratingly, its the ObservableCollection with children of children of children I am having trouble generating in the first place.
I have a table in SQL with LDAP Paths, and various other information I'm storing against that LDAP path, which I read into my ObservableCollection.
Single level, no problem, the bit I'm struggling with is sorted the sub objects of sub objects by LDAP Path, so when I bind to the treeview is presented as AD OU's are structured.
EG:
TopOU
Users
Front Office Users
Helpdesk Users
Example LDAP Paths in my DB
LDAP://OU=Front Office Users,OU=Users,OU=TopOU,DC=dev,DC=local
LDAP://OU=Helpdesk Users,OU=Users,OU=TopOU,DC=dev,DC=local
LDAP://OU=OU=Users,OU=TopOU,DC=dev,DC=local
LDAP://OU=OU=TopOU,DC=dev,DC=local
private ObservableCollection<AssignmentData> OUTreeAssignmentsCollection = new ObservableCollection<AssignmentData>();
public class AssignmentData : INotifyPropertyChanged
{
public Int32 AssignmentID { get; set; }
public String AssignmentName { get; set; }
public AssignmentTypes AssignmentType { get; set; }
//other stuff....
//For TreeView all sub nodes
public ObservableCollection<AssignmentData> Children { get; set; }
}
I then start to read from my db in a rather nasty way, and this is where it all goes wrong, and I could use some pointers.
cmd = new SqlCommand("SELECT UserGroups.UserGroupID, UserGroups.Name, UserGroups.LDAPPath FROM UserGroups WHERE UserGroups.TypeID=1", DBCon);
reader = cmd.ExecuteReader();
while (reader.Read())
{
String strLDAPHierarchical = GetLDAPHierarchical(reader[2].ToString());
AssignmentData newItem = new AssignmentData()
{
AssignmentID = Convert.ToInt32(reader[0]),
AssignmentName = reader[1].ToString(),
AssignmentImage = ouIcon,
AssignmentLDAPPath = reader[2].ToString(),
AssignmentCNPath = GetCNFromLDAPPath(reader[2].ToString()),
AssignmentTooltip = GetADSLocationTooltip(reader[2].ToString()),
AssignmentType = AssignmentTypes.UserOU,
AssignmentLDAPHierarchical = strLDAPHierarchical
};
if (strLDAPHierarchical.Contains(","))
{
//Now check all the root nodes exist to continue
String strLDAPHierarchicalCheckPath = strLDAPHierarchical;
String[] SplitLDAPHierarchical = strLDAPHierarchical.Split(new Char[] { ',' });
Int32 reverseI = SplitLDAPHierarchical.Length - 1;
String prevPath = "";
for (int i = 0; i < SplitLDAPHierarchical.Length; i++)
{
String path = SplitLDAPHierarchical[reverseI];
//now check if this node is already there and if not look it up and create it
if (path != "")
{
if (i == 0) { strLDAPHierarchicalCheckPath = path; }
else { strLDAPHierarchicalCheckPath = path + "," + prevPath; }
WriteLog("CHECK:" + strLDAPHierarchicalCheckPath);
LookupItemByLDAPHierarchical(strLDAPHierarchicalCheckPath, newItem);
if (i == 0) { prevPath = path; }
else { prevPath = path + "," + prevPath; }
reverseI = reverseI - 1;
}
}
}
else
{
//is top level object, so create at the root of the collection
UserOUCollection.Add(newItem);
}
Function to add sub items :-/
internal AssignmentData LookupItemByLDAPHierarchical(String strLDAPHierarchical, AssignmentData fromItem)
{
AssignmentData currentItem = null;
foreach (AssignmentData d in UserOUCollection)
{
if (d.AssignmentLDAPHierarchical == strLDAPHierarchical) { currentItem = d; break; }
if (d.Children != null)
{
currentItem = CheckChildNodesByLDAPHierarchical(d, strLDAPHierarchical);
if (currentItem != null) { break; }
}
}
String strMessage = "null";
if (currentItem != null) { strMessage = currentItem.AssignmentLDAPPath; }
if (currentItem == null)
{
String strWhere = "LDAPPath LIKE 'LDAP://" + strLDAPHierarchical + "%'";
SqlConnection DBCon = new SqlConnection(SQLString);
DBCon.Open();
SqlCommand cmd = new SqlCommand("SELECT UserGroupID, Name, LDAPPath FROM UserGroups WHERE " + strWhere + " AND TypeID=1", DBCon);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
strLDAPHierarchical = GetLDAPHierarchical(reader[2].ToString());
AssignmentData newItem = new AssignmentData()
{
AssignmentID = Convert.ToInt32(reader[0]),
AssignmentName = reader[1].ToString(),
AssignmentImage = ouIcon,
AssignmentLDAPPath = reader[2].ToString(),
AssignmentCNPath = GetCNFromLDAPPath(reader[2].ToString()),
AssignmentTooltip = GetADSLocationTooltip(reader[2].ToString()),
AssignmentType = AssignmentTypes.UserOU,
AssignmentLDAPHierarchical = strLDAPHierarchical
};
String strLDAPHierarchicalCheckPath = strLDAPHierarchical;
foreach (String path in strLDAPHierarchical.Split(new Char[] { ',' }))
{
//now check if this node is already there and if not look it up and create it
if (path != "")
{
strLDAPHierarchicalCheckPath = strLDAPHierarchicalCheckPath.Replace(path + ",", "");
currentItem = LookupItemByLDAPHierarchical(strLDAPHierarchicalCheckPath, currentItem);
if (null == currentItem)
{
UserOUCollection.Add(newItem); //new root item
}
else
{
if (currentItem.Children == null)
{
//add new child
currentItem.Children = new ObservableCollection<AssignmentData> { newItem };
}
else
{
//add more children to exisiting
currentItem.Children.Add(newItem);
}
}
currentItem = null;
}
}
//Find a current Item to add the node to
//currentItem = LookupItemByLDAPHierarchical(strLDAPHierarchical);
}
reader.Close();
reader.Dispose();
DBCon.Close();
DBCon.Dispose();
}
return currentItem;
}
With my current solution, I get a treeview, with sub nodes of sub nodes, but they are wrong/lots of duplication etc. I have spent literally days trying to fix my probably overcomplicated attempt above - but have come to the conclusion I'm probably going about it the wrong way.
Any help greatly appreciated!
Just having a peruse ;) through your code. Think I can see why you have lots of duplications. Looks like your first SQL query get's all parent/child records. Then the second query will go and get some of those records again, if that makes sense.
One approach would be to only get the top level items in your first query. Possibly by getting SQL to count the number of commas.
SELECT UserGroups.UserGroupID, UserGroups.Name, UserGroups.LDAPPath,
LENGTH(LDAPPath) - LENGTH(REPLACE(LDAPPath, ',', '')) as CommaCount
FROM UserGroups
WHERE UserGroups.TypeID=1
AND CommaCount = 2
Since you asked for different approach id say it's not very efficient to repeatedly query the database in a loop. When I'm building a tree of parent child objects I'd normally get all parent/child records in one query. Build a flat dictionary of all the objects. Then loop through it and make the parent/child associations.
The dictionary can also be useful to lookup your objects later on either directly by key or to loop through without having to make a recursive function that crawls the tree.
So I'd suggest that you break it down into 2 blocks of code.
First block: Using your existing query that get's all of the items, create a flat Dictionary with everything in.
They key of each item should probably be the result from GetLDAPHierarchical().
Second block: Next loop through the dictionary and create the hierarchy. Add anything with no parent directly to the UserOUCollection
foreach(AssignmentData d in myDictionary.Values)
{
String parentKey = GetParentLDAPKey(d.AssignmentLDAPHierarchical);
if (myDictionary.ContainsKey(parentKey))
{
myDictionary(parentKey).children.Add(d);
}
else
{
UserOUCollection.Add(d);
}
}
GetParentLDAPKey() will need to produce the same key as it's parent by removing the first part of the LDAP Path.
Hope that points you in the right direction.
H
(SMASH)
Thanks so much to hman, who pointed me in a much more logical direction. I used LDAPPath as my dictionary key.
Dictionary<String, AssignmentData> OUDictionary = new Dictionary<String, AssignmentData>();
//Read from DB
cmd = new SqlCommand("SELECT UserGroups.UserGroupID, UserGroups.Name, UserGroups.LDAPPath FROM UserGroups WHERE UserGroups.TypeID=1", DBCon);
reader = cmd.ExecuteReader();
while (reader.Read())
{
AssignmentData newItem = new AssignmentData()
{
AssignmentID = Convert.ToInt32(reader[0]),
AssignmentName = reader[1].ToString(),
AssignmentImage = ouIcon,
AssignmentLDAPPath = reader[2].ToString(),
AssignmentCNPath = GetCNFromLDAPPath(reader[2].ToString()),
AssignmentTooltip = GetADSLocationTooltip(reader[2].ToString()),
AssignmentType = AssignmentTypes.UserOU,
};
UserOUDictionary.Add(reader[2].ToString(), newItem);
}
reader.Close();
reader.Dispose();
//Now Read OU List into TreeView Collection
foreach (AssignmentData d in UserOUDictionary.Values)
{
String parentKey = GetParentLDAPPath(d.AssignmentLDAPPath);
if (UserOUDictionary.ContainsKey(parentKey))
{
AssignmentData parentItem = UserOUDictionary[parentKey];
if (parentItem.Children == null) { parentItem.Children = new ObservableCollection<AssignmentData> { d }; } //add first child
else { parentItem.Children.Add(d); } //add more children to exisiting
}
else
{
UserOUCollection.Add(d); //add to root of control
}
}
private String GetParentLDAPKey(String strLDAPPath)
{
String retParentKey = strLDAPPath;
if (strLDAPPath.Contains(","))
{
retParentKey = retParentKey.Replace("LDAP://", "");
retParentKey = retParentKey.Remove(0, retParentKey.IndexOf(",") + 1);
retParentKey = "LDAP://" + retParentKey;
}
return retParentKey;
}

Check if value exist in a List C#

I have a DataTable that is filled by a Stored Procedure, and from that datatable which contains a collection of Requests(RequestNumber and Tasks(TaskId). When I have reach the first Request number with a Task, I add it to my list, then with additional datarows, I check the list to see if they exist(if(dr["RequestNumber"].ToString() != acList[i].RequestNumber)) if they do, I delete the dataRow, if not I add them to the list.
This works good in sequential order, but if the datarow and list are off by one it allows the row to be added. Is there any other way to accomplish finding if the value exists in the list.
Thanks in advance.
foreach (DataRow dRow in dt.Rows)
{
DataRow dr = dt.NewRow();
dr["Project"] = dRow["Project"];
dr["RequestNumber"] = dRow["RequestNumber"];
dr["RequestId"] = dRow["RequestId"];
dr["TaskType"] = dRow["TaskType"];
dr["TaskId"] = dRow["TaskId"];
dr["TaskStatus"] = dRow["TaskStatus"];
dr["AssignedTo"] = dRow["AssignedTo"];
dr["DateDue"] = dRow["DateDue"];
if (acList.Count == 0)
{
acList.Add(new AssignedClass
{
Project = dr["Project"].ToString(),
RequestNumber = dr["RequestNumber"].ToString(),
RequestId = dr["RequestId"].ToString(),
TaskType = dr["TaskType"].ToString(),
TaskId = dr["TaskId"].ToString(),
TaskStatus = dr["TaskStatus"].ToString(),
AssignedTo = dr["AssignedTo"].ToString(),
DateDue = dr["DateDue"].ToString()
});
}
else
{
for (int i = 0; i < acList.Count; i++)
{
if(dr["RequestNumber"].ToString() != acList[i].RequestNumber)
{
acList.Add(new AssignedClass
{
Project = dr["Project"].ToString(),
RequestNumber = dr["RequestNumber"].ToString(),
RequestId = dr["RequestId"].ToString(),
TaskType = dr["TaskType"].ToString(),
TaskId = dr["TaskId"].ToString(),
TaskStatus = dr["TaskStatus"].ToString(),
AssignedTo = dr["AssignedTo"].ToString(),
DateDue = dr["DateDue"].ToString()
});
}
else
{
dr.Delete();
}
}
}
Using LINQ, it's as simple as checking if there are any matches:
if ( !acList.Any(a => a.RequestNumber == dr["RequestNumber"].ToString() )
acList.Add( ... );
Also, it seems that the code at the beginning assigning dRow to dr has no purpose. Just use dRow directly throughout the rest of your code. And I don't think you want to treat (acList.Count == 0) as a special case, because that just causes you to have to duplicate your logic and thus maintain two separate copies of the same code. So if I understood everything correctly, this simplified code should accomplish the same thing:
foreach (DataRow dRow in dt.Rows)
{
if ( !acList.Any(a => a.RequestNumber == dRow["RequestNumber"].ToString() )
{
acList.Add(new AssignedClass
{
Project = dRow["Project"].ToString(),
RequestNumber = dRow["RequestNumber"].ToString(),
RequestId = dRow["RequestId"].ToString(),
TaskType = dRow["TaskType"].ToString(),
TaskId = dRow["TaskId"].ToString(),
TaskStatus = dRow["TaskStatus"].ToString(),
AssignedTo = dRow["AssignedTo"].ToString(),
DateDue = dRow["DateDue"].ToString()
});
}
}
This would be a great job for LINQ's Union method, but it requires an IEqualityComparer<AssignedClass> implementation. Unless you do this often, it's probably not worth coding (even though it's 10-ish lines if done properly). This would help, however:
acList = acList
.Concat(from row in dt.Rows
from ac in acList
where ac.RequestNumber != row["RequestNumber"].ToString()
select AssignedClassFromDataRow(row))
.ToList();
where
private static AssignedClass AssignedClassFromDataRow(DataRow row)
{
// maybe some checks...
return new AssignedClass
{
Project = dRow["Project"].ToString(),
RequestNumber = dRow["RequestNumber"].ToString(),
RequestId = dRow["RequestId"].ToString(),
TaskType = dRow["TaskType"].ToString(),
TaskId = dRow["TaskId"].ToString(),
TaskStatus = dRow["TaskStatus"].ToString(),
AssignedTo = dRow["AssignedTo"].ToString(),
DateDue = dRow["DateDue"].ToString()
}
}
Slightly more time complex than a hash-based solution, but simple enough to implement.
EDIT:
If you actually need the extra performance provided by hashing, you can write the EqualityComparer (but keep in mind these guidelines). Such solution would look like this in the end:
acList = acList
.Union(
dt.Rows.Select(AssignedClassFromDataRow),
new MyAssignedClassRequestNumberComparer())
.ToList();
You can use HashSet<AssignedClass>, all you need is to create custom IEqualityComarer<AssignedClass> in which you check RequestNumber property of passed objects, and pass instance of this comparer in constructor of HashSet
Edit
Here is possible implementation of IEqualityComarer<AssignedClass> :
public class AssignedClassComparer : IEqualityComparer<AssignedClass>
{
public bool Equals(AssignedClass x, AssignedClass y)
{
return x.RequestNumber == y.RequestNumber;
}
public int GetHashCode(AssignedClass obj)
{
return obj.RequestNumber.GetHashCode();
}
}
EDIT2:
Or you can simply use HashSet to store only keys, while enumerating through rows:
var keys = new HashSet<string>();
foreach (DataRow dRow in dt.Rows)
{
if (keys.Add(dRow["RequestNumber"].ToString()))
{
acList.Add(new AssignedClass
{
Project = dRow["Project"].ToString(),
RequestNumber = dRow["RequestNumber"].ToString(),
RequestId = dRow["RequestId"].ToString(),
TaskType = dRow["TaskType"].ToString(),
TaskId = dRow["TaskId"].ToString(),
TaskStatus = dRow["TaskStatus"].ToString(),
AssignedTo = dRow["AssignedTo"].ToString(),
DateDue = dRow["DateDue"].ToString()
});
}
}
With the option of linq and taking into account that the beginning code block and the check for 0 entries seem a bit redundant. I think the process could boil down to
var distinctRows = dt.Rows.GroupBy(x => x["RequestNumber"]).Select(x => x.First());
acList.AddRange(distinctRows.Select(x => x.MapToAssignedClass());
// Added Mapping method for readability
public static AssignedClass MapToAssignedClass(this DataRow dr)
{
return new AssignedClass
{
Project = dr["Project"].ToString(),
RequestNumber = dr["RequestNumber"].ToString(),
RequestId = dr["RequestId"].ToString(),
TaskType = dr["TaskType"].ToString(),
TaskId = dr["TaskId"].ToString(),
TaskStatus = dr["TaskStatus"].ToString(),
AssignedTo = dr["AssignedTo"].ToString(),
DateDue = dr["DateDue"].ToString()
});
}

Categories

Resources