MVC3 query clause custom query - c#

First Table
+--------+------------+-------+
| type | variety | price |
+--------+------------+-------+
| apple | gala | 2.79 |
| apple | fuji | 0.24 |
| apple | limbertwig | 2.87 |
| orange | valencia | 3.59 |
| orange | navel | 9.36 |
| pear | bradford | 6.05 |
| pear | bartlett | 2.14 |
| cherry | bing | 2.55 |
| cherry | chelan | 6.33 |
+--------+------------+-------+
Second Table
+--------+----------+
| type | minprice |
+--------+----------+
| apple | 0.24 |
| cherry | 2.55 |
| orange | 3.59 |
| pear | 2.14 |
+--------+----------+
select type, min(price) as minprice
from fruits
group by type;
The first table is and example of the data that I have and the second table is what I want to get from the first.
I am using GenericRepository/UnitOfwork to get the data from repository.
repository.fruitRepository.Get().GroupBy(m => m.type);
But I can only get the type field but I want to get more fields.
Do I need to use a select clause before groupby? If yes, how can I select more fields?

The GroupBy method returns more data, but it's returned as an enumerable... you may be able to pull what you want out of it with a Select after the GroupBy...
repository.fruitRepository.Get()
.GroupBy(m => m.type)
.Select(m => new { type = m.Key, minPrice = m.Min(f => f.Price) });
Or if you prefer a LINQ statement:
var result = from x in repository.fruitRepository.Get()
group x by x.type into typeGroup
select new
{
type = typeGroup.Key,
minPrice = typeGroup.Min(item => item.Price)
};

Related

Advance LINQ Ordering in Xamarin Forms

I have an ObservableCollection<myListType> Items.
Each item in Items has a Project Name which can be "Administrative" and "Non-Administrative"(can be anything). I want to sort my Items using LINQ so that the items with Non-Administrative Project Name will be put on top of Administrative item.
So far i use,
Items.OrderBy(x => x.ProjectName != "Administrative").ThenBy(x => x.ProjectName == "Administrative");
But it doesn't sort the way i want and when i debug, I saw
"The Expression not supported".
Any ideas?
How you use OrderBy and ThenBy shows a lock of understanding how OrderBy works. Please see the following example
| ID | Project Name |
-----------------------
| 1 | Administrative |
| 2 | X |
| 3 | Administrative |
| 4 | X |
With the expression x.ProjectName != "Administrative", OrderBy will look at all items and sort them by whether ProjectName is not "Administrative".
| ID | Project Name | ProjectName != "Administrative" |
---------------------------------------------------------
| 1 | Administrative | false |
| 2 | X | true |
| 3 | Administrative | false |
| 4 | X | true |
This will yield the following order
| ID | Project Name | ProjectName != "Administrative" |
---------------------------------------------------------
| 1 | Administrative | false |
| 3 | Administrative | false |
| 2 | X | true |
| 4 | X | true |
because true is deemed greater by OrderBy. ThenBy now tries to order the groups internally, i.e. all items that matched a single "order key" are tried to be ordered by another criteria. See the following table for visualization
| ID | Project Name | ProjectName != "Administrative" |
---------------------------------------------------------
| 1 | Administrative | false | Items for false
| 3 | Administrative | false |
=========================================================
| 2 | X | true | Items for true
| 4 | X | true |
Since ProjectName == "Administrative" has the same value for all items withing a single group, no subsequent ordering happens.
How can you achieved the desired outcome?
Simply use
Items.OrderBy(x => x.ProjectName == "Administrative")
Since ProjectName == "Administrative" is true for all administrative projects and true is deemed greater by OrderBy they show up last.
According to your requirements, "Non-Administrative" should be put on top of "Administrative".
You can do this:
var list = Items.OrderByDescending(x => x.ProjectName);
it will put "Non-Administrative" before "Administrative".
Edited
[for non-administrative name that has 'AAA']:
var result = Items.OrderBy(p => p.ProjectName == "Administrative").ThenBy(p => p.ProjectName);
Demo on dotnet fiddle
You make sure ProjectName == "Administrative" is always on the bottom.
var result = Items.OrderBy(p => p.ProjectName == "Administrative");

Comparison with multiple Where clause in LINQ C#

I have two DataTables:
DataTable dtCatalogFromMySql;
DataTable dtDataForExistingProducts;
dtCatalogFromMySql
Id | productname | barcode | pricesell| type
---+--------------+----------+----------+------
1 | Abz | 123 | 2.01 | RS // different product name
2 | Abd | 122 | 8.90 | RS // different price
3 | Abx | 125 | 21.00 | WS // both different
4 | Abf | 124 | 2.11 | RS
5 | Abg | 126 | 8.01 | WS
6 | Abh | 127 | 60.23 | RS
7 | Abi | 128 | 9.10 | RS
dtDataForExistingProducts
Id | productname | barcode | pricesell| type
---+--------------+----------+----------+------
1 | Abc | 123 | 2.01 | RS
2 | Abd | 122 | 3.90 | RS
3 | Abe | 125 | 23.00 | WS
4 | Abf | 124 | 2.11 | RS
5 | Abg | 126 | 8.01 | WS
6 | Abh | 127 | 60.23 | RS
7 | Abi | 128 | 9.10 | RS
I need return only rows which are different as in first table
I need select all data where Prod_No equals to baracode and Descript not equals to productname and Retail_PRC also not equals to pricesell.
I am not getting results with this code
List<DataRow> matchingRows = dtCatalogFromMySql.AsEnumerable()
.Where(a => dtDataForExistingProducts.AsEnumerable()
.Select(b => b.Field<string>("Prod_No"))
.Contains(a.Field<string>("barcode")))
.Where(a => !dtDataForExistingProducts.AsEnumerable()
.Select(b => b.Field<string>("Descript"))
.Equals(a.Field<string>("productname")))
.Where(a => !dtDataForExistingProducts.AsEnumerable()
.Select(b => b.Field<decimal>("Retail_PRC"))
.Equals(Convert.ToDecimal(a.Field<double>("pricesell"))))
.ToList();
I suppose, Contains() will also fetch the data if barcode = 123456 and Prod_No = 1234, it is right? If I am right what is right way to compare string exactly same
You may want to consider a clearer syntax such as:
var results = from t1 in dtCatalogFromMySql.AsEnumerable()
join t2 in dtDataForExistingProducts.AsEnumerable() on
(string)t1["barcode"] equals (string)t2["Prod_No"]
where (string)t1["productname"] != (string)t2["descript"] &&
Convert.ToDecimal((double)t1["pricesell"]) !=
(decimal)t2["Retail_PRC"]
select t2;
The Join is definitely the way to go. You can modify the select according to your required result set.
trighati makes a good point about using OR instead of AND. This is assuming that you want all of the data where at least one of your values changed where Prod_no and barcode are equal. This would change the query to be:
var results = from t1 in dtCatalogFromMySql.AsEnumerable()
join t2 in dtDataForExistingProducts.AsEnumerable() on
(string)t1["barcode"] equals (string)t2["Prod_No"]
where (string)t1["productname"] != (string)t2["descript"] ||
Convert.ToDecimal((double)t1["pricesell"]) !=
(decimal)t2["Retail_PRC"]
select t2;
Use Join to combine them into one result set, then filter the result set:
var combined = dtDataForExistingProducts.AsEnumerable()
.Join(dtCatalogFromMySql.AsEnumerable(),
ep => ep.Field<string>("Prod_No")
ce => ce.Field<string>("barcode"),
(ep, ce) => new {ExistingProduct = ep, CatalogEntry = ce})
.Where(m => !m.ExistingProduct.Field("Descript")
.Equals(m.CatalogEntry.Field("productname")))
.Where(m => decimal.Parse(m.ExistingProduct.Field("Retail_PRC").ToString())
!= decimal.Parse(m.CatalogEntry.Field("pricesell").ToString()))
.ToList()
;

Entity Framework get one of each combination by date

I'm using Entity Framework in ASP.NET. I have something like a table like this:
+----+--------------------------+-------+-------+------------+
| id | content | type1 | type2 | date |
+----+--------------------------+-------+-------+------------+
| 0 | Some text | TypeA | TypeB | 2013-04-01 |
| 1 | Some older text | TypeB | TypeA | 2012-03-01 |
| 2 | Some even older texttext | TypeB | TypeC | 2011-01-01 |
| 3 | A dog | TypeC | TypeB | 2013-04-01 |
| 4 | And older dog | TypeC | TypeB | 2012-03-01 |
| 5 | An even older dog | TypeA | TypeC | 2011-01-01 |
| 6 | More text | TypeA | TypeB | 2013-03-01 |
+----+--------------------------+-------+-------+------------+
I already can obtain the most recent occurrence of type 1 or type 2, but I want to query the database to obtain the most recent occurrence of the combination of two types:
+----+--------------------------+-------+-------+------------+
| id | content | type1 | type2 | date |
+----+--------------------------+-------+-------+------------+
| 0 | Some text | TypeA | TypeB | 2013-04-01 |
| 3 | A dog | TypeC | TypeB | 2013-04-01 |
| 5 | An even older dog | TypeA | TypeC | 2011-01-01 |
+----+--------------------------+-------+-------+------------+
Thanks!
EDIT: The columns type1 or type2 are basically the same, so if Type1=A and Type2=B it's the same as Type1=B and Type2=A.
This would do the trick, except for one little issue, which I'll describe after the code sample.
var grouped = datacontext.Table
.GroupBy(
item => new { item.Type1, item.Type2 },
(key, groupData) => groupData.OrderBy(x => x.TheDate).First())
.ToArray();
The problem is that this way the grouping is done on the combination of Type1 and Type2, in that order. So what you are saying in the comments, which is that Type1=A AND Type2=B is equal to Type1=B AND Type2=A is a problem.
I really have no idea if EF (or L2S) can compile this, but it is worth a try.
var grouped = datacontext.Table
.Select(x => new Data // TODO: Update to the correct typename
{
x.Id,
x.Content,
Type1 = x.Type1.CompareTo(x.Type2) > 0 ? x.Type2 : x.Type1,
Type2 = x.Type1.CompareTo(x.Type2) > 0 ? x.Type1 : x.Type2,
x.TheDate
})
.GroupBy(
item => new { item.Type1, item.Type2 },
(key, groupData) => groupData.OrderBy(x => x.TheDate).First())
.ToArray();
If the above doesn't compile, then an alternative option is to correct the Type1/Type2 values after the database-grouping, and perform the grouping again in-memory. Yes, this means it will group twice (once by the database, once in-memory), but it will work, and won't require to import the complete table into memory.
var grouped = datacontext.Table
.GroupBy(
item => new { item.Type1, item.Type2 },
(key, groupData) => groupData.OrderBy(x => x.TheDate).First())
.AsEnumerable()
.GroupBy(
item => new {
// Group by the possible-swapped-values of Type1 and Type2
Type1 = x.Type1.CompareTo(x.Type2) > 0 ? x.Type2 : x.Type1
Type2 = x.Type1.CompareTo(x.Type2) > 0 ? x.Type1 : x.Type2
},
(key, groupData) => groupData.OrderBy(x => x.TheDate).First())
.ToArray();
I think I like the last option the best, since:
it can be translated to sql (no special features like string.CompareTo)
at most it will be twice the amount of records that the database will yield, not anymore (which in my opinion is acceptable without knowing the amount of total data we're talking about)

linq select a new, by list of columns names

I have a dataTable that I get from DB,
And I want to retrieve the data by linq
my dataTable From DB
+-----------------+-----------------+-----------------+
| column_1 | column_2 | column_3 |
+-----------------+-----------------+-----------------+
| data_column_1_1 | data_column_2_1 | data_column_3_1 |
| data_column_1_2 | data_column_2_2 | data_column_3_2 |
| data_column_1_3 | data_column_2_3 | data_column_3_3 |
| data_column_1_4 | data_column_2_4 | data_column_3_4 |
+-----------------+-----------------+-----------------+
I do not know the number of columns in the table
but did I get another table with the names of all columns
the column's names
+----------------+
| column's names |
+----------------+
| column_1 |
| column_2 |
| column_3 |
+----------------+
How do I do this?
I want it to look like this
        
  
  var list = DataTableFromDB.AsEnumerable (). Select (x => new
{
row1 = x.Field <string> ("row1"),
  row2 = x.Field <string> ("row2"),
});
But dynamically,
can help me?
Use ExpandoObject and Add() method(with cast to IDictionary) to add dynamic property to Expanded Object.
Code:
var list = DataTableFromDB.AsEnumerable().Select(x =>
{
var sampleObject = new ExpandoObject();
foreach (var col in columnsNames)
{
((IDictionary<String, Object>)sampleObject)
.Add(col, x.Field<string>(col));
}
return sampleObject;
});

How do you duplicate rows based on a quantity in a cell? LINQ to Entities

I have an Orders table and an Assignments table which I join together using LINQ to Entities. Each order has a product and a quantity. Each order has a number of assignments up to the quantity. I want to output the following:
Orders:
ID | OrderCode | Quantity | Other Columns...
1 | 30000-1 | 3 | ...
2 | 41000-7 | 2 | ...
Assignments:
OrderID | Assignment | Other Columns...
1 | 4526 | ...
2 | 2661 | ...
2 | 5412 | ...
I want to output a table like:
OrderCode | Assignment
30000-1 | 4526
30000-1 |
30000-1 |
41000-7 | 2661
41000-7 | 5412
Any advice would be welcome!
I would split the task up into three parts.
First, I'd use LINQ to Entities to get the full collection of orders, each with it's corresponding collection of assignments:
var a = (from o in orders
join a in assignments on s.Id equals a.OrderId into oa
//Notice that I use oa.DefaultIfEmpty(). This essentially the way to do a
//LEFT JOIN in LINQ. You'll want to do a LEFT JOIN if you don't
//want to exclude order codes that have no assignments
select new { o.OrderCode, o.Quantity, Assignments = oa.DefaultIfEmpty() })
.ToList();
a returns the following for your example:
OrderCode | Assignment
30000-1 | 4526
41000-7 | 2661
41000-7 | 5412
Then I'd add the "missing" rows
var b = a.SelectMany(o =>
{
var numOrdersInList = o.Count(o2 => o2.OrderCode == o.OrderCode);
return Enumerable.Range(0, o.Quantity - numOrdersInList)
.Select(i => new
{
o.OrderCode,
Assignment = Enumerable.Empty<Assignment>()
});
});
b returns the following for your example:
OrderCode | Assignment
30000-1 |
30000-1 |
Then I'd concat the two enumerables.
var c = a.Select(o => new { o.OrderCode, o.Assignment })
.Concat(b);
Finally, the concatenation should return what you expect for your example:
OrderCode | Assignment
30000-1 | 4526
30000-1 |
30000-1 |
41000-7 | 2661
41000-7 | 5412

Categories

Resources