What is the most efficient way to retrieve distinct column values. I have a table with fields FormsID and ProductLineDescription along with other columns. ProductLine table has a one to many relationship, the sample data in the table would be like:
FormID ProdculineDesc
1 abc
2 abc
1 xyz
2 def
3 abc
3 xyz
I want the dropdown to have just the distinct values of ProductLineDesc. Here is the code,
private void LoadProductLines(Models.SearchModel Model, xyzEntities Context)
{
Model.ProductLine = Context.PRODUCTLINEs
.OrderBy(T => T.FormsGuid).ToSelectList().Distinct();
}
This still gives me every ProductLineDesc, how do I retrieve just the Distinct values.
Here's a version with a custom quality comparer (with example):
public class UniqueProductLineDesc : IEqualityComparer<Product>
{
public Boolean Equals(Product a, Product b)
{
if (Object.ReferenceEquals(a, b))
return true;
if (Object.ReferenceEquals(a, null) || Object.ReferenceEquals(b, null))
return false;
return String.Compare(a.ProductLineDesc, b.ProductLineDesc, true) == 0;
}
public Int32 GetHashCode(Product product)
{
if (Object.ReferenceEquals(product, null))
return 0;
return product.ProductLineDesc == null ? 0 : product.ProductLineDesc.GetHashCode();
}
}
And to implement:
private void LoadProductLines(Models.SearchModel Model, xyzEntities Context)
{
Model.ProductLine = Context.PRODUCTLINEs
.OrderBy(T => T.FormsGuid)
.ToSelectList()
.Distinct(new UniqueProductLineDesc());
}
How about something like:
var distinctInfo = (from c in Context.PRODUCTLINEs
group by c.ProductLineDesc into result
select new Model.ProductLine {
ProductLineDesc = result.Key,
FormID = result.Min(d=>d.FormID)
});
Related
I have a table with orders(around 8000 records),
The table takes a few seconds to load.
The reason for that is because one of the field shown on the page is being retrieved from another table
(returnProductName).
when removing this function the table loads fast.
When loading the records I'm using Skip and Take but when retrieving the product name i'm iterating all the Orders since if the user wants to search by product name it will show all results with this product.
The product table is not big (around 70 records)
I can't figure out why the function will make the page load so slow.
I know i can just add the product name column to the table and populate it when ever adding new orders,
but this doesn't sounds right,
Can anyone tell me the reason for this delay?
returnProductName Function :
public string returnProductName(int productId)
{
return (_unitOfWork.Product.GetAll().Where(q => q.Id == productId).Select(q =>
q.ProductName)).FirstOrDefault();
}
Function that loads the page data:
[HttpPost]
public ActionResult GetList()
{
//Server Side parameters
int start = Convert.ToInt32(Request.Form["start"].FirstOrDefault());
int length = Convert.ToInt32(Request.Form["length"].FirstOrDefault());
string searchValue = Request.Form["search[value]"].FirstOrDefault();
string sortColumnName = Request.Form["columns["+Request.Form["order[0][column]"]+"][name]"].FirstOrDefault();
string sortDirection = Request.Form["order[0][dir]"].FirstOrDefault();
List<Order> orderList = new List<Order>();
orderList = _unitOfWork.Order.GetAll().ToList();//Working Fast
int totalRows = orderList.Count;
foreach (Order order in orderList)
{
order.ProductName = returnProductName(order.ProductId);
}
if (!string.IsNullOrEmpty(searchValue))
{
orderList = orderList.Where(x => x.FullAddress.ToLower().Contains(searchValue.ToLower())
x.Id.ToString().Contains(searchValue.ToLower()) ||
x.OrderStatus.ToLower().Contains(searchValue.ToLower()) ||
x.ProductName.ToLower().Contains(searchValue.ToLower()) |||
x.Quantity.ToString().Contains(searchValue.ToLower()) ||
x.Cost.ToString().Contains(searchValue.ToLower()) ||
(!string.IsNullOrEmpty(x.TrackingNumber) && x.TrackingNumber.ToString().Contains(searchValue.ToLower()))
).ToList<Order>();
}
int totalRowsAfterFiltering = orderList.Count;
orderList = orderList.Skip(start).Take(length).ToList<Order>();
return Json(new { data = orderList, draw = Request.Form["draw"], recordsTotal = totalRows ,
recordsFiltered = totalRowsAfterFiltering});
}
I would perhaps consider updating the GetAll() method or creating another one which returns a dictionary.
In this case GetAllById() and then updating returnProductName which I would rename to GetProductName():
// Or whatever your type is
public Dictionary<int, List<Product>> GetAllById()
{
// your code..
return data
.GroupBy(x => x.Id)
.ToDictionary(x => x.Key, x => x.ToList());
}
public string GetProductName(int productId)
{
var products = _unitOfWork.Product.GetAllById();
return products[productId].FirstOrDefault(q => q.ProductName);
}
how I can update a single value for an already existing row in the db by only having a parameters that I want to add it to this attribute
here is my code for a trivial way but didnt work
public bool BuyBook(int BookId, int UserId, int BookPrice){
using (var ctx = new OnlineBooksEntities())
{
User updatedCustomer = (from c in ctx.Users
where c.UserId == UserId
select c).FirstOrDefault();
updatedCustomer.Balance = BookPrice;
ctx.SaveChanges();
}
this.DeleteBook(BookId);
return true;
}
Add an sql query to the method solves the update aim
public bool BuyBook(int BookId, int UserId, int BookPrice)
{
try
{
using (var ctx = new OnlineBooksEntities())
{
User user = ctx.Users.Where(x => x.UserId == UserId).FirstOrDefault();
BookPrice = (int)user.Balance + BookPrice;
int noOfRowUpdated =
ctx.Database.ExecuteSqlCommand("Update Users set Balance = "+BookPrice+ " where UserId ="+UserId);
}
Updating basically means changing an existing row's value. Since you mentioned EF, you can do this by retrieving the object, changing its value, and saving it back. Thus you can do something like this:
using (var db = new MyContextDB())
{
var result = db.Books.SingleOrDefault(b => b.BookPrice == bookPrice);
if (result != null)
{
result.SomeValue = "Your new value here";
db.SaveChanges();
}
}
I Create A News Site With MVC5 But I Have Problem .
in Model i Create A Repository Folder And in this i Create Rep_Setting for
Connect to Tbl_Setting in DataBase .
public class Rep_Setting
{
DataBase db = new DataBase();
public Tbl_Setting Tools()
{
try
{
var qGetSetting = (from a in db.Tbl_Setting
select a).FirstOrDefault();
return qGetSetting;
}
catch (Exception)
{
return null;
}
}
}
And i Create a Rep_News for Main Page .
DataBase db = new DataBase();
Rep_Setting RSetting = new Rep_Setting();
public List<Tbl_News> GetNews()
{
try
{
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals("News")
select a).OrderByDescending(s => s.ID).Skip(0).Take(RSetting.Tools().CountNewsInPage).ToList();
return qGetNews;
}
catch (Exception ex)
{
return null;
}
}
But This Code Have Error to Me
OrderByDescending(s=>s.ID).Skip(0).Take(RSetting.Tools().CountNewsInPage).ToList();
Error :
Error 18 'System.Linq.IQueryable<NewsSite.Models.Domain.Tbl_News>' does
not contain a definition for 'Take' and the best extension method overload
'System.Linq.Queryable.Take<TSource>(System.Linq.IQueryable<TSource>, int)' has
some invalid arguments
E:\MyProject\NewsSite\NewsSite\Models\Repository\Rep_News.cs 50 52 NewsSite
How i Resolve it ?
Try it this way. The plan of debugging is to split your execution, this also makes for a more reusable method in many cases. And a good idea is to avoid using null and nullables if you can, if you use them "on purpose" the you must have a plan for them.
DataBase db = new DataBase();
Rep_Setting RSetting = new Rep_Setting();
public List<Tbl_News> GetNews()
{
int skip = 0;
Tbl_Setting tools = RSetting.Tools();
if(tools == null){ throw new Exception("Found no rows in the database table Tbl_Setting"); }
int? take = tools.CountNewsInPage;//Nullable
if(!take.HasValue)
{
// Do you want to do something if its null maybe set it to 0 and not null
take = 0;
}
string typeStr = "News";
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals(typeStr)
select a).OrderByDescending(s => s.ID).Skip(skip).Take(take.Value);
return qGetNews.ToList();
}
if qGetNews is a empty list you now don't break everything after trying to iterate on it, like your return null would. instead if returning null for a lit return a new List<>() instead, gives you a more resilient result.
So I said reusable method, its more like a single action. So you work it around to this. Now you have something really reusable.
public List<Tbl_News> GetNews(string typeStr, int take, int skip = 0)
{
List<Tbl_News> qGetNews = (from a in db.Tbl_News
where a.Type.Equals(typeStr)
select a).OrderByDescending(s => s.ID).Skip(skip).Take(take);
return qGetNews.ToList();
}
Infact you shjould always try to avoid returning null if you can.
public class Rep_Setting
{
DataBase db = new DataBase();
public Tbl_Setting Tools()
{
var qGetSetting = (from a in db.Tbl_Setting
select a).FirstOrDefault();
if(qGetSetting == null){ throw new Exception("Found no rows in the database table Tbl_Setting"); }
return qGetSetting;
}
}
I'm doing Join algorithm in MapReduce. In the Map phase, I made joinColumn as key and the tuple as value. In the reduce method, I have keys and values as (columnname, row). In the reduce phase, I need to separate the "row" into two based on which table they belong to.
I used MultiMap to do this. But the MultiMap is overwriting the existing value. To try to overcome this, I override "equals" and "hashcode" but this did not fix the problem.
public void reduce(Text key,Iterable<Text> values,Context context) throws IOException, InterruptedException{
Multimap<String,Table> entry=LinkedListMultimap.create();
for(Text val : values){
String[] row=val.toString().split(",");
Table t = new Table();
t.setTablename(row[0]);
t.setColumns(val);
entry.put(row[0],t);
}
for (String k: entry.keySet()){
System.out.println("Key : "+k);
Collection<Table> rows=entry.get(k);
Iterator<Table> i=rows.iterator();
while(i.hasNext()){
Table t=i.next();
System.out.println(t.getColumns());
}
}
public class Table {
private String tablename;
private Text columns;
public String getTablename() {
return tablename;
}
public void setTablename(String tablename) {
this.tablename = tablename;
}
public Text getColumns() {
return columns;
}
public void setColumns(Text columns) {
this.columns = columns;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((columns == null) ? 0 : columns.hashCode());
result = prime * result
+ ((tablename == null) ? 0 : tablename.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Table other = (Table) obj;
if (columns == null) {
if (other.columns != null)
return false;
} else if (!columns.equals(other.columns))
return false;
if (tablename == null) {
if (other.tablename != null)
return false;
} else if (!tablename.equals(other.tablename))
return false;
return true;
}
}
I'm getting the following output:
Key : S
R, 2, Don, Larson, Newark, 555-3221
R, 2, Don, Larson, Newark, 555-3221
Key : R
R, 2, Don, Larson, Newark, 555-3221
Key : S
R, 3, Sal, Maglite, Nutley, 555-6905
R, 3, Sal, Maglite, Nutley, 555-6905
Key : R
R, 3, Sal, Maglite, Nutley, 555-6905
Key : R
S, 4, 22000, 7000, part1
Key : S
S, 4, 22000, 7000, part1
It is overriding the existing values. Can anyone help me to sort out this problem?
Your problem is that the object returned by iterating over values is reused by the iterator. Instead of just assigning the value in setColumns(), you need to copy it. Something like:
public void setColumns(Text columns) {
this.columns = new Text(columns.toString());
}
I am working on getting the results of this sql query in LINQ
SELECT DISTINCT(Type)
FROM Product
WHERE categoryID = #catID
this is my repository query:
public IQueryable<ProdInfo> GetProdInfo()
{
var data = from u in db.Prod
select new ProdInfo
{
PID = u.PID,
CatID = u.CatID,
LastChanged = u.LastChanged,
ChangedBy = u.ChangedBy,
Type = u.Type,
};
return data;
}
filter:
public static IQueryable<ProdInfo> GetDistinctProdType(this IQueryable<ProdInfo> qry,int CatID)
{
return from p in qry
where p.CatID.Equals(CatID)
select p;
}
I need the filter to return the distinct prod type? How can i do this?
Simply like this:
public static IQueryable<ProdType> GetDistinctProdType(
this IQueryable<ProdInfo> query,
int categoryId)
{
return (from p in query
where p.CatID == categoryId
select p.Type).Distinct();
}
Note that I've changed the return type - it should match whatever the type of ProdInfo.Type is.
You may find it more readable to use the extension methods for the whole query if the query expression itself is reasonably simple:
public static IQueryable<ProdType> GetDistinctProdType(
this IQueryable<ProdInfo> query,
int categoryId)
{
return query.Where(p => p.CatID == categoryId)
.Select(p => p.Type)
.Distinct();
}
return (from p in qry
where p.CatId.Equals(CatID)
select p.Type).Distinct();
This matches what your provided SQL Query should be doing.