Converting from dataset to list in linq - linq

I have dataset function which is as below,
public DataSet GetUpodBrandList(string criteria, string locationId)
{
using (SqlConnection conn = new SqlConnection(this.ConnectionString))
{
string query;
if (criteria == "")
query = "select distinct brandDesc " +
"from arabia_upod_item_master " +
"where locationId = '" + locationId +
"' order by brandDesc";
else
query = "select distinct brandDesc " +
"from arabia_upod_item_master " +
"where brandDesc like '%" + criteria + "%' " +
"and locationId = '" + locationId + "'
order by brandDesc";
conn.Open();
SqlCommand command = new SqlCommand(query, conn);
return this.ExecuteDatasetStoredProc(command);
}
}
I am trying to convert it into linq as follow,
public static List<DataContext.arabia_upod_item_master> GetUpodBrandList(
string criteria,
string locationId)
{
List<DataContext.arabia_upod_item_master> m =
new List<DataContext.arabia_upod_item_master>();
using (var db = UpodDatabaseHelper.GetUpodDataContext())
{
db.ObjectTrackingEnabled = false;
if (criteria == "")
m = db.arabia_upod_item_masters.Where(
i => i.locationId == Convert.ToInt32(locationId))
.OrderBy(i => i.brandDesc)
.Distinct()
.ToList();
else
m = db.arabia_upod_item_masters.Where(
i => i.brandDesc.Contains(criteria) &&
i.locationId == Convert.ToInt32(locationId))
.OrderBy(i => i.brandDesc)
.Distinct()
.ToList();
return m;
}
}
But I don't know how to select distinct brandDesc in the above function (as in the previous function). I am simply using Distinct(). Is it right? or is there any other way to achieve it? Also, if there was 'case' in query in my old function (i.e the first one above) then how will i convert it to linq in the second function. Any other things to worry about while converting to linq?

Put a .Select(i => i.brandDesc) just before each Distinct call. You'll also need to change your List<x> so x is whatever the type of brandDesc is.
If I were to refactor you whole method, I'd do something like the following. I've pulled out code that is common to both forms of the query, and tweaked in a couple of other places.
public static IList<string/* I assume*/>GetUpodBrandList(
string criteria, string locationId)
{
// only do this once, not once per item.
int locatId = Convert.ToInt32(locationId);
using (var db = UpodDatabaseHelper.GetUpodDataContext())
{
db.ObjectTrackingEnabled = false;
// This is a common start to both versions of the query.
var query = db.arabia_upod_item_masters
.Where(i => i.locationId == locatId);
// This only applies to one version of the query.
if (criteria != "")
{
query = query.Where(i => i.brandDesc.Contains(criteria));
}
// This is a common end to both version of the query.
return query
.Select(i => i.brandDesc)
.Distinct()
// Do the ordering after the distinct as it will
// presumably take less effort?
.OrderBy(i => i.brandDesc)
.ToList();
}
}

Related

PredicateBuilder to Query Comma Delimited String in Linq

I am trying to query a comma delimited string using PredicateBuilder. My data set has DAYS in TR format which means Tuesday and Thursday, but my parameter query string will be passed in this way: Day=T,R. My query does not return any data right now so I guess have to use like '%' to get data. Can anyone tell me where the problem is in my linq query below:
public List<myTable> Get(string filter1 = null, string Day = null)
{
if (string.IsNullOrWhiteSpace(filter1) && string.IsNullOrWhiteSpace(Day) )
return new List<myTable>();
IQueryable<myTable> qry = db.myTable.AsQueryable();
var searchPredicate = PredicateBuilder.True<myTable>();
if (filter1 !=null){
searchPredicate = searchPredicate.And(a => a.Column1.Contains(filter1)
}
if (Day != null)
{
//split day string
string[] items = Day.Split(',');
foreach (var item in items)
{
searchPredicate = searchPredicate.And(a => items.Contains("%" + a.DAYS + "%"));
}
}
return qry.where(searchPredicate).ToList();
}
Or, how to create a where Predicate like this: where column1='filter' and (DAYS like 'T%' or DAYS like 'M%') ? Thanks.

create extension method in linq

How to create an extension method to the string to get a sum
create Sumstring extension method
List<myclass> obj=new List<myclass>()
{
new myclass(){ID=1,name="ali",number=1},
new myclass(){ID=1,name="karimi",number=2},
new myclass(){ID=2,name="mohammad",number=4},
new myclass(){ID=2,name="sarbandi",number=5},
};
var query = (from p in obj
group p by p.ID into g
select new
{ id = g.Key, sum = g.Sumstring(p => p.name) }).ToList();
dataGridView1.DataSource=query;
I connect to the database
What is the code
You've not specified what SumString really returns, but looks like you're talking about string concatenation of all source collection elements.
It can be easily done using String.Join method:
public static class EnumerableOfString
{
public static string SumString<TSource>(this IEnumerable<TSource> source, Func<TSource, string> selector, string separator = null)
{
return String.Join(separator ?? string.Empty, source.Select(i => selector(i)));
}
}
That method allows following calls:
g.SumString(p => p.name)
with string.Empty as default deparator and with custom separator specified:
g.SumString(p => p.name, ",")
If all you want to do is concatenate the strings in that group you can use the built-in Aggregate function:
var query = (from p in obj
group p by p.ID into g
select new
{ id = g.Key, sum = g.Aggregate((tot, next) => tot + "," + next) }
).ToList();

Get only one value from the table using LINQ

I have a Customer Table and a Address Table (customer_id, address_forename, address_surname, address_street, address_city, address_zip,
address_storedtime) where customer_id as a foreign key.
One customer can have several address.
Now I am trying to get only the last entered address using LINQ as bellow which should allow me put the address in a string and return that:
CODE:
var customerAddress = (from c in myDB.address
where (c.customer_id == customerId)
select new
{
c.customer_id,
c.address_forename,
c.address_surname,
c.address_street,
c.address_city,
c.address_zip,
c.address_storedtime
}).GroupBy(g => new
{
Customer = .customer_id,
Address = g.address_forename + " " + g.address_surname + " " + g.address_street + " " + g.address_city + " " + g.address_zip
}).Select(g => new
{
g.Key.Customer,
g.Key.Address,
StoredTime = g.Max(x => x.address_storedtime)
}).Disinct();/*First();*/
string result = "";
foreach (var ad in customerAddress)
{
if (ad.Address != null)
{
result = ad.Address;
}
break;
}
return result;
I am getting same address string for different addresses in DB for the Customer whereas I am trying to get only one.
Since you're already filtering by customer id, the grouping clause isn't necessary. You should be able to just order the results for the customer descending and project the address much more simply.
var customerAddress = (from c in myDB.address
where (c.customer_id == customerId)
orderby c.address_storedtime descending
select c.address_forename + " " + c.address_surname + " " + c.address_street + " " + c.address_city + " " + c.address_zip)
.FirstOrDefault();
Replace your foreach by
var result =
customerAdress.Any(ad => ad.Address != null)
? customerAdress.Last(ad => ad.Address != null).Address
: default(string);

Date fiIter Issues in LINQ

I have an ASPX page that collects 5 optional search criteria from a user and returns the result in a grid. Once the criteria are collected and the view button clicked, the code behind generates the filter like we have below
// aSearchCriteria is a class that holds the criteria
...
string filter = string.Empty;
if (!string.IsNullOrEmpty(aSearchCriteria.RegistrationNumber)) filter =
"f.BusinessRegistrationNumber = '" +
aSearchCriteria.BusinessRegistrationNumber + "'";
if (aSearchCriteria.ChangedStartDate != null && aSearchCriteria.ChangedEndDate != null)
{
if (!string.IsNullOrEmpty(filter))
{
filter += " && f.ChangedDate >= '" +
aSearchCriteria.ChangedStartDate.ToShortDateString() +
"' && f.ChangedDate <= '" +
aSearchCriteria.ChangedEndDate.ToShortDateString() + "'";
}
else
{
...
}
}
...
Using (CustomerEntities db = new CustomerEntities())
{
if (!string.IsNullOrEmpty(filter))
{
filter = "f => " + filter;
**return db.Customers.Where(filter).ToList();**
}
else
...
}
...
Sample:
"filter" value: f => f.ChangedDate > '01/01/2012' && f.ChangedDate < '14/01/2012'
Anytime I execute this I get this error message:
The query syntax is not valid. Near term '>', line 6, column 5.
you don't want to make the filter a string. What you should do instead is apply the filtering to the IQueryable you get. Something like:
var customers = db.Customers.AsQueryable();
if (aSearchCriteria.ChangedStartDate != null && aSearchCriteria.ChangedEndDate != null)
{
customers = customers
.Where(c => c.ChangedDate >= aSearchCriteria.ChangedStartDate &&
c.ChangedDate >= aSearchCriteria.ChangedEndDate);
}
// ... apply other filters as necessary
return customers.ToList();
Assuming you are using ObjectQuery.Where(string)
the string predicate should look like
"it.ChangedDate > '01/01/2012' && it.ChangedDate < '14/01/2012'"
(no f=> and the alias of the table is it)
Please confirm it helped :)

How to optimize code for Sorting?

I would like to optimize following lines of code for Sorting.
public ViewResult Index(string sortorder, int? pagesize, int? page)
{
int pageSize = pagesize ?? 10;
if (Request.HttpMethod != "GET")
{
page = 1;
pageSize = 10;
}
ViewBag.SelectedPageSize = pageSize;
ViewBag.CurrentSort = sortorder;
ViewBag.FirstNameSortParm = String.IsNullOrEmpty(sortorder) ? "FirstName desc" : "";
ViewBag.LastNameSortParm = sortorder == "LastName" ? "LastName desc" : "LastName";
ViewBag.DepNameSortParm = sortorder == "depName" ? "depName desc" : "depName";
var joined = from tm in db.TabMasters select tm;
switch (sortorder)
{
case "FirstName":
joined = joined.OrderBy(m => m.FirstName);
break;
case "FirstName desc":
joined = joined.OrderByDescending(m => m.FirstName);
break;
case "LastName":
joined = joined.OrderBy(m => m.LastName);
break;
case "LastName desc":
joined = joined.OrderByDescending(m => m.LastName);
break;
case "depName":
joined = joined.OrderBy(m => m.depName);
break;
case "depName desc":
joined = joined.OrderByDescending(m => m.depName);
break;
default:
joined = joined.OrderBy(m => m.FirstName);
break;
}
int pageIndex = (page ?? 1) - 1;
int start = (pageIndex * pageSize);
ViewBag.TotalRecord = joined.Count();
ViewBag.StartRecord = start + 1;
ViewBag.EndRecord = ((start + pageSize) >= ViewBag.TotalRecord) ? ViewBag.TotalRecord : (start + pageSize);
return View(joined.ToPagedList(pageIndex, pageSize));
}
Because this is very tedious way if i have more the 10 fields to perform sort.
Thanks,
Imdadhusen
It's a bit vague to me what your actual goal is but for the switch part you could use an extension method as the below.
public static class SortExtensions
{
public static IEnumerable<T> SortByField<T>(this IEnumerable<T> sequence, string sortOrder)
{
var tokens = sortOrder.Trim().Split(' ');
var field = tokens[0];
var direction = tokens.Skip(1).Single().ToLower();
var prop = typeof(T).GetProperty(field);
return direction == "desc"
? sequence.OrderByDescending(m => prop.GetValue(m, null))
: sequence.OrderBy(m => prop.GetValue(m, null));
}
}
It will make a very simplified parsing of the sort order. It puts the responsibility on the calling party which is generally not what you want to do, so you might want some error handling in case the sortorder string does not fulfill the requirements.
from the sortorder string it fetches a name used to identify a property which can be used to fetch the value used for sorting.
you can use it like this:
db.TabMasters.SortByField(sortOrder)
EDIT based on comment:
The line typeof(T).GetProperty(field) is fragile in the absence of any error handling. It relies on the first token to be a name of a public property of the type T. It will return null if the name doesn't match a property. Including if it matches a Field name. A similar function exist for getting a FieldInfo
prop.GetField(field) will return a fieldinfo object of there's a public field with the given name otherwise null. To get the value of a field simply omit the last parameter to the GetValue call.
You should take a look at Linq.DynamicQuery.
There's more info in this blogpost http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
The library lets you write following code:
var query = northwind.Products
.Where("CategoryID = 3 AND UnitPrice > 3")
.OrderBy("SupplierID");
instead of
var query = from p in northwind.Products
where p.CategoryID == 3 && p.UnitPrice > 3
orderby p.SupplierID
select p;
If you want to add the sortdirection:
var query = northwind.Products.OrderBy("SupplierID Descending");

Resources