How to simplify the code Using LINQ - c#

I need to know how to implement the below logic to get the list of items with the help of LINQ without using foreach. Also, I need to exclude those matching Items from item List after adding the item into new list.
Code
List<StockResult> Stockres = new List<StockResult>();
foreach (var stkitms in item)
{
if (Db.Stk.Any(a => a.INo == stkitms.ItemNum))
{
StockResult ss = new StockResult();
ss.ItemNumber = stkitms.ItemNum;
ss.FileName = stkitms.FileName;
Stockres.Add(ss);
}
}
Any solution to this will be appreciated.

You could try this one:
List<StockResult> Stockres = item.Where(x=>Db.Stk.Any(a => a.INo == x.ItemNum))
Select(x=> new StockResult()
{
ItemNumber = x.ItemNum,
FileName = x.FileName
}).ToList();

Related

How to add distinct value in database using Entity Framework

IEnumerable<WebsiteWebPage> data = GetWebPages();
foreach (var value in data)
{
if (value.WebPage.Contains(".htm"))
{
WebsiteWebPage pagesinfo = new WebsiteWebPage();
pagesinfo.WebPage = value.WebPage;
pagesinfo.WebsiteId = websiteid;
db.WebsiteWebPages.Add(pagesinfo);
}
}
db.SaveChanges();
I want to add only distinct values to database in above code. Kindly help me how to do it as I am not able to find any solution.
IEnumerable<WebsiteWebPage> data = GetWebPages();
foreach (var value in data)
{
if (value.WebPage.Contains(".htm"))
{
var a = db.WebsiteWebPages.Where(i => i.WebPage == value.WebPage.ToString()).ToList();
if (a.Count == 0)
{
WebsiteWebPage pagesinfo = new WebsiteWebPage();
pagesinfo.WebPage = value.WebPage;
pagesinfo.WebsiteId = websiteid;
db.WebsiteWebPages.Add(pagesinfo);
db.SaveChanges();
}
}
}
This is the code that I used to add distinct data.I hope it helps
In addition to the code sample Furkan Öztürk supplied, Make sure your DB has a constraint so that you cannot enter duplicate values in the column. Belt and braces approach.
I assume that by "distinct values" you mean "distinct value.WebPage values":
// get existing values (if you ever need this)
var existingWebPages = db.WebsiteWebPages.Select(v => v.WebPage);
// get your pages
var webPages = GetWebPages().Where(v => v.WebPage.Contains(".htm"));
// get distinct WebPage values except existing ones
var distinctWebPages = webPages.Select(v => v.WebPage).Distinct().Except(existingWebPages);
// create WebsiteWebPage objects
var websiteWebPages = distinctWebPages.Select(v =>
new WebsiteWebPage { WebPage = v, WebsiteId = websiteid});
// save all at once
db.WebsiteWebPages.AddRange(websiteWebPages);
db.SaveChanges();
Assuming that you need them to be unique by WebPage and WebSiteId
IEnumerable<WebsiteWebPage> data = GetWebPages();
foreach (var value in data)
{
if (value.WebPage.Contains(".htm"))
{
WebsiteWebPage pagesinfo = new WebsiteWebPage();
if (db.WebsiteWebPages.All(c=>c.WebPage != value.WebPage|| c.WebsiteId != websiteid))
{
pagesinfo.WebPage = value.WebPage;
pagesinfo.WebsiteId = websiteid;
db.WebsiteWebPages.Add(pagesinfo);
}
}
}
db.SaveChanges();
UPDATE
To optimize this (given that your table contains much more data than your current list), override your equals in WebsiteWebPage class to define your uniqueness criteria then:
var myWebsiteWebPages = data.select(x=> new WebsiteWebPage { WebPage = x.WebPage, WebsiteId = websiteid}).Distinct();
var duplicates = db.WebsiteWebPages.Where(x=> myWebsiteWebPage.Contains(x));
db.WebsiteWebPages.AddRange(myWebsiteWebPages.Where(x=> !duplicates.Contains(x)));
this is a one database query to retrieve ONLY duplicates and then removing them from the list
You can use the following code,
IEnumerable<WebsiteWebPage> data = GetWebPages();
var templist = new List<WebsiteWebPage>();
foreach (var value in data)
{
if (value.WebPage.Contains(".htm"))
{
WebsiteWebPage pagesinfo = new WebsiteWebPage();
pagesinfo.WebPage = value.WebPage;
pagesinfo.WebsiteId = websiteid;
templist.Add(pagesinfo);
}
}
var distinctList = templist.GroupBy(x => x.WebsiteId).Select(group => group.First()).ToList();
db.WebsiteWebPages.AddRange(distinctList);
db.SaveChanges();
Or you can use MoreLINQ here to filter distinct the list by parameter like,
var res = tempList.Distinct(x=>x.WebsiteId).ToList();
db.WebsiteWebPages.AddRange(res);
db.SaveChanges();

Creating method to use one foreach instead multiple

I'm working with c#, and I have working code where I repeated same code every line, and that's because I'm creating list, conversions , extracting data etc.
So I have multiple foreach clauses,multiple lists, multiple conversions of list to datatables. My question is, what can I do to re-factorize this in order to have clean code?
Code:
private void BtnLoadReport_Click(object sender, EventArgs e)
{
var db = new SQLDataMgr();
List<string> DesignStatusList = new List<string>();
List<string> ShopStatusList = new List<string>();
List<string> CustomerTypeList = new List<string>();
List<string> CustomerList = new List<string>();
List<string> ResellerList = new List<string>();
List<string> StateList = new List<string>();
List<string> ProjectManagerList = new List<string>();
List<string> SalesRepresentativeList = new List<string>();
var checkedDesignStatus = cboDesignStatus.CheckBoxItems.Where(x => x.Checked);
var checkedShopStatus = cboShopStatus.CheckBoxItems.Where(x => x.Checked);
var checkedCustomerType = cboShopStatus.CheckBoxItems.Where(x => x.Check
var checkedCustomer = cboShopStatus.CheckBoxItems.Where(x => x.Checked);
var checkedReseller = cboShopStatus.CheckBoxItems.Where(x => x.Checked);
var checkedState = cboShopStatus.CheckBoxItems.Where(x => x.Checked);
var checkedProjectManager = cboShopStatus.CheckBoxItems.Where(x => x.Checked);
var checkedSalesRepresentative = cboShopStatus.CheckBoxItems.Where(x => x.Checked);
foreach (var i in checkedDesignStatus)
{
DesignStatusList.Add(i.Text);
}
foreach (var i in checkedShopStatus)
{
ShopStatusList.Add(i.Text);
}
foreach (var i in checkedCustomerType)
{
CustomerTypeList.Add(i.Text);
}
foreach (var i in checkedCustomer)
{
CustomerList.Add(i.Text);
}
foreach (var i in checkedReseller)
{
ResellerList.Add(i.Text);
}
foreach (var i in checkedState)
{
StateList.Add(i.Text);
}
foreach (var i in checkedProjectManager)
{
ProjectManagerList.Add(i.Text);
}
foreach (var i in checkedSalesRepresentative)
{
SalesRepresentativeList.Add(i.Text);
}
DataTable designStatusParameters = ToStringDataTable(DesignStatusList);
DataTable shopStatusParameters = ToStringDataTable(ShopStatusList);
DataTable customerTypeParameters = ToStringDataTable(CustomerTypeList);
DataTable customerParameters = ToStringDataTable(CustomerList);
DataTable resellerParameters = ToStringDataTable(ResellerList);
DataTable stateParameters = ToStringDataTable(StateList);
DataTable projectManagerParameters = ToStringDataTable(ProjectManagerList);
DataTable salesRepresentativerParameters = ToStringDataTable(SalesRepresentativeList);
}
Change ToStringDataTable to an Extension Method. Then:
var designStatusParameters = cboDesignStatus.CheckBoxItems.Where(x => x.Checked)
.Select(i => i.Text).ToList().ToStringDataTable();
You can even write the extension method for your control in a way that performs filtering, projection and converting to data table for you then you can have:
var designStatusParameters = cboDesignStatus.ToStringDataTable();
You can cut out all the foreach loops by using Linq's Select():
For example:
var DesignStatusList =
cboDesignStatus.CheckBoxItems
.Where(x => x.Checked)
.Select(i => i.Text)
.ToList();
That will leave you with a List<string> containing all the Text properties from the checked CheckBoxes.
You could even skip declaring the list and combine that with your DataTable creation lines:
var designStatusParameters = ToStringDataTable(
cboDesignStatus.CheckBoxItems
.Where(x => x.Checked)
.Select(i => i.Text)
.ToList());
I would suggest putting this in a method of its own rather than repeating this over and over for each group of checkboxes.
Just keep in mind that less lines of code doesn't mean faster performance. It still has to iterate through the lists to find the right values. But it is much more readable than being hit in the face with a wall of repetitive code.
You don't need those many foreach rather re-factor to a single method like
public void AddToList(List<string> listToAdd, List<CheckBox> listToIterate)
{
foreach (var i in listToIterate)
{
listToAdd.Add(i.Text);
}
}
You are taking unnecessary expicit steps making your code way more verbose than it should be.
You are doing in separate steps:
Make an empty list.
Filter data
Iterate filtered data and add it to the empty list.
When you can do:
var newList =
someCollection.Where(someFilter)
.Select(someProjection)
.ToList();
That will make the code much more readable.
And, if you are in the mood, you can even make a helper method where you pass in someCollection, someFilter and someProjection and returns a list of something.
The code below isn't quite right, but I'd recommend that you build one generic method that returns a DataTable and you call that method over and over. Something like this:
public DataTable getDataTable( CheckBox yourCheckBox)
{
DataTable returnTable = new DataTable();
List<string> tempList = new List<string>();
var checkedDesignStatus = yourCheckBox.CheckBoxItems.Where(x => x.Checked);
foreach (var i in checkedDesignStatus)
{
tempList.Add(i.Text);
}
returnTable = ToStringDataTable(tempList);
return returnTable;
}
Create method (maybe local method?)
DataTable CheckedToDataTable(YourContainerType container)
=> ToStringDataTable(container.CheckBoxItems.Where(x => x.Checked).Select(x => x.Text).ToList());

Stepping out of foreach after finding right productID

Each of our products are based on a certain categoryID
When looping through our products it has to first find the product within that category (which it does) and then step out of it. The problem is that when it has gone through the foreach the first time (finding the right prouducts) it does not step out, it just keeps going through it finding the remainding products with other categoryIDs.
How do we solve this?
(We are using C# - Entity Framework - MSSQL)
CHEERS!
public ActionResult Index(int id)
{
var m = new Models.Product.Index();
//m.DisplayName = "Produkter";
//var scp = db.SCPconnection.FirstOrDefault(s => s.CategoryID == id);
//if (id == scp.ProductID)
{
foreach (var item in db.Product.OrderBy(p => p.ProductName))
{
var mp = new Models.Product.ModelProduct();
mp.SectorName = item.ProductName;
mp.ProductID = item.ProductID;
mp.DetailsUrl = item.Details;
m.AllProducts.Add(mp);
}
}
return View(m);
}
Just break it.
foreach (var item in db.Product.OrderBy(p => p.ProductName))
{
var mp = new Models.Product.ModelProduct();
mp.SectorName = item.ProductName;
mp.ProductID = item.ProductID;
mp.DetailsUrl = item.Details;
m.AllProducts.Add(mp);
if(condition) //if it is needed
break;
}
It is better to filter using Where clause for a particular ID.
I would strongly suggest Optimized code, why would you require to get all Products details to business logic, instead query for what is needed with a condition.
foreach (var item in db.Product.Where(p => p.ProductID.Equals(requiredID)).OrderBy(p => p.ProductName))
{
var mp = new Models.Product.ModelProduct();
mp.SectorName = item.ProductName;
mp.ProductID = item.ProductID;
mp.DetailsUrl = item.Details;
m.AllProducts.Add(mp);
}
The break keyword immediately exits the foreach at that point. Code after the break and remaining iteration items will NOT be processed.
public ActionResult Index(int id)
{
var m = new Models.Product.Index();
foreach (var item in db.Product.OrderBy(p => p.ProductName))
{
var mp = new Models.Product.ModelProduct();
mp.SectorName = item.ProductName;
mp.ProductID = item.ProductID;
mp.DetailsUrl = item.Details;
m.AllProducts.Add(mp);
if (item.ProductID == id)
break;
}
}
return View(m);
}

How to avoid repeating when I get data from stored procedure?

I get a list from stored procedure with its child date I want to avoid repeating when I add items to the the list
Here is my code:
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[T]";
db.Database.Connection.Open();
var reader1 = cmd.ExecuteReader();
var objectContext1 = ((IObjectContextAdapter)db).ObjectContext;
var usersLi = objectContext1.Translate<GetAllNewsForUser>(reader1).ToList();
List<GetAllNewsForUser> lll = new List<GetAllNewsForUser>();
foreach (var item in usersLi)
{
NewsInfo newsInfo = new NewsInfo();
GetAllNewsForUser g = new GetAllNewsForUser();
g.UserName = item.UserName;
NewsInfo nnn = new NewsInfo();
nnn.NewsTitle = item.NewsTitle;
nnn.NewsId = item.NewsId;
g.NewsInfos.Add(nnn);
lll.Add(g);
}
are there any unique identifiers for g, for example a user Id. in which case you could easily use the following:
if (!lll.Any(x=>x.UserId ==g.UserId)) //include system.linq
{
lll.Add(g);
}
You could also look at modifying your stored procedure to not return duplicates.
EDIT ----
Just twigged as to what you actually after, sorry.....
Its just a rough draft but i think this is what you require.
List<GetAllNewsForUser> lll = new List<GetAllNewsForUser>();
foreach (var item in usersLi)
{
NewsInfo nnn = new NewsInfo();
nnn.NewsTitle = item.NewsTitle;
nnn.NewsId = item.NewsId;
if (!lll.Any(x=> x.UserName == item.UserName)
{
GetAllNewsForUser g = new GetAllNewsForUser();
g.UserName = item.UserName;
g.NewsInfos.Add(nnn);
lll.Add(g);
}
else
{
lll.Where(x=>x.UserName == item.Username).FirstOrDefault().NewsInfos.Add(nnn)
}
}
From what I understand so far, you are trying to avoid adding same rows in the list(based on value of some column).
LINQ might help here.
usersLi.GroupBy(e => new {
UserID = e.UserUD
}).Select(g => g.First());

Add items to list from IEnumerable using LinQ

I'm adding new items to a list from a IEnumerable (query.Roles).
var query = GetRoles();
var vm = new CreateUserViewModel();
vm.Role = new List<CreateUserViewModel.Item>();
foreach (var Role in query.Roles)
{
vm.Role.Add(new CreateUserViewModel.Item
{
Label = Role.Label,
RoleNumber = Role.RoleNumer
});
}
How i can do the 'Add' to the list with Linq?
AddRange should do it for you:
vm.Role.AddRange(query.Roles.Select(r => new CreateUserViewModel.Item
{
Label = r.Label,
RoleNumber = r.RoleNumer
}));
AddRange takes an IEnumerable parameter and adds each item to the collection.
vm.Role = query
.Roles
.Select(r=>new CreatUserViewModel
.Item{Label = r.Label,
RoleNumber = r.RoleNumber})
.ToList();

Categories