Dynamic sorting with nullable column - linq

I am writing dynamic sorting with lambda expression as below:
string sortColumn = imageFilterType == 1 ? "CreatedDate" : "AbuseCount";
var paramExp = Expression.Parameter(typeof(Items), typeof(Items).ToString());
Expression propConvExp = Expression.Convert(Expression.Property(paramExp, sortColumn), typeof(object));
var sortExp = Expression.Lambda<Func<Items, object>>(propConvExp, paramExp);
Above I am creating dynamic sort column and I am applying this sortexpression in bellow query:
var items = _db.Items.AsQueryable()
.AsExpandable()
.OrderByDescending(sortExp)
.Where(predicate)
.Select(x => x)
.Join(_db.Users, i => i.UserId, u => u.UserID, (i, u) => new
{
i,
FullName = u.UserType == 1 ? u.FirstName + " " + u.LastName : u.CompanyName,
u.UserType,
u.UserName
})
.ToList()
.Skip(pageIndex)
.Take(pageSize);
I have 2 columns in input by which I have to sort data one is CreatedDate and another is Abusecount. I have to apply sorting with one column among both of them. but as I am trying to run above code I am getting error:
"Unable to cast the type 'System.Nullable`1' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types."
Since in my database both column is of nullable type thatswhy I am getting this problem. Is anyone have solution of this problem? I don't want to change in DB. I have to solve it from fron end only.

Try this, it's much simplier:
var items = _db.Items.AsQueryable()
.AsExpandable();
if (imageFilterType == 1)
items=items.OrderByDescending(a=>a.CreatedDate);
else
items=items.OrderByDescending(a=>a.AbuseCount);
items=items.Where(predicate)
.Select(x => x)
.Join(_db.Users, i => i.UserId, u => u.UserID, (i, u) => new
{
i,
FullName = u.UserType == 1 ? u.FirstName + " " + u.LastName : u.CompanyName,
u.UserType,
u.UserName
})
.Skip(pageIndex)
.Take(pageSize)
.ToList();

Related

NDepend: how to export the result from a query

I've got a CQLinq query which returns a list of methods and a list of members for each of them. Exporting the query result will only show the number of elements. I thought about using a Linq Aggregate( (a,b) => a + ',' + b). Is there a better solution?
let type = Application.Types.WithFullName("WPF.ViewModels.CouponViewModel").Single()
let dicoFields = type.Fields
.ToDictionary(f => f, f => f.MethodsUsingMe.Where(m => m.ParentType == f.ParentType))
let dicoMethods = type.Methods
.ToDictionary(m => m, m => m.MembersUsed.Where(f => f.ParentType == m.ParentType))
// The partition algorithm on both dicos here
//from pair in dicoFields
//orderby pair.Value.Count() descending
//select new { pair.Key, pair.Value }
from pair in dicoMethods
orderby pair.Value.Count() descending
select new { pair.Key, pair.Value}
Indeed you can rewrite your query this way:
let type = Application.Types.WithFullName("WPF.ViewModels.CouponViewModel").Single()
let dicoMembers = type.ChildMembers
.ToDictionary(x => x, x =>
x.IsField ? x.AsField.MethodsUsingMe.Where(m => m.ParentType == x.ParentType):
x.AsMethod.MembersUsed.Where(f => f.ParentType == x.ParentType))
from pair in dicoMembers
orderby pair.Value.Count() descending
select new {
pair.Key,
str = pair.Value.Any() ?
pair.Value.Select(x => x.Name).Aggregate( (a,b) => a + " ; " + b) :
"empty"
}
Both methods and fields are taken account
Methods using fields and members used by methods are aggregated in a string
Then you can export the result:

Except keyword issue in LINQ

I want to capture the column names which needs to be added to the SQL table in order to insert the data.
Columnspresent-- List of all columns in the file ("Node", "Logtime", "Reason","ID","Comments")
existingtablecolumnsPresent -- List of all columns in the existing table in SQL("Node","Value","Reason","ID","Comments","logtime")
columnsNotPresent -- List of columns that needs to be added to the SQL table ( have to get "Value" in the output but not getting)..
List<string> columnsPresent =
dt.Columns.Cast<DataColumn>()
.Select(a => a.ColumnName.ToLower())
.ToList();
List<string> existingtablecolumnsPresent =
existingtable.Columns.Cast<DataColumn>()
.Select(a => "[" + a.ColumnName.ToLower() + "]")
.ToList();
List<string> columnsNotPresent =
columnsPresent.OrderBy(t => t)
.Except(existingtablecolumnsPresent.OrderBy(t => t))
.ToList();
The above code is not giving the correct results if there is change in order of columns .Please advise.
you may try this (it needn't order by..)
List<string> existingtablecolumnsPresentNoSqrBr = new List<string>();
existingtablecolumnsPresent.ForEach(c => {
c = c.Replace("[", string.Empty);
c = c.Replace("]",string.Empty);
existingtablecolumnsPresentNoSqrBr.Add(c);
});
List<string> columnsNotPresent =
columnsPresent.Except(existingtablecolumnsPresentNoSqrBr)
.ToList();
really, if you avoid to .Select(a => "[" + a.ColumnName.ToLower() + "]") you can use the second query directly on existingtablecolumnsPresent..

Linq GROUP & SUM the same columns from different tables

I'm trying to combine these 2 Linq queries into 1:
var query = from s in _context.Set<StockInventoryItem>()
where s.StockCatalogueItemId == id
group s by s.StockType into g
select new
{
inStock = g.Sum(x => x.QtyInStock),
};
var query2 = from p in _context.Set<PurchaseOrderItem>()
where p.StockCatalogueItemId == id
group p by p.StockType into g2
select new
{
onOrder = g2.Sum(x => x.QtyStillDue)
};
Note that the filtering, grouping and output is the same from both tables, and I want the results to look like this:
StockType inStock onOrder
+----------+--------+--------+
Type 1 4 3
+----------+--------+--------+
Type 2 0 1
i.e. Quantities grouped by StockType
This is EF code first and there is no direct relationship between these tables, which is why I'm trying this query in the service layer so I can access both entities.
You should be able to "shoehorn" both groups into the same sequence with anonymous types and Concat, and then count the results separately, like this:
var query = _context.Set<StockInventoryItem>()
.Where(ii => ii.StockCatalogueItemId == id)
.Select(ii => new {
II = ii, PO = (PurchaseOrderItem)null
}).Concat(_context.Set<PurchaseOrderItem>()
.Where(po => po.StockCatalogueItemId == id)
.Select(po => new {
II = (StockInventoryItem)null, PO = po
})).GroupBy(p => II != null ? ii.StockType : PO.StockType)
.Select(g => new {
InStock = g.Sum(p => p.II != null ? p.II.QtyInStock : 0)
, OnOrder = g.Sum(p => p.PO != null ? p.PO.QtyStillDue: 0)
});

Convert piece of code into LINQ (short syntax)

I want to convert this LINQ code
var x = from nm in names
select MyClass.SomeMethod(nm).TrimStart(',');
foreach (var vv in x)
{
// I want to group and count different types of vv here
}
to use shorter syntax, one where they do x => x in LINQ. I also want to group and count 'vv' (there could be number of similar vv's)
Well, the "dot notation" or "fluent notation" for the above is:
var x = names.Select(nm => MyClass.SomeMethod(nm).TrimStart(','));
For grouping:
var x = names.Select(nm => MyClass.SomeMethod(nm).TrimStart(','));
.GroupBy(vv => vv,
(key, group) => new { Key = key, Count = group.Count() });
Something like this?
MyClass.SomeMethod(names).TrimStart(',')
.GroupBy(x => x.vv)
.ToList()
.ForEach(x => Console.WriteLine(x.Key + ": " + x.Count()));

Update existing list values with values from another query

I have a linq statement which calls a stored proc and returns a list of items and descriptions.
Like so;
var q = from i in doh.usp_Report_PLC()
where i.QTYGood == 0
orderby i.PartNumber
select new Parts() { PartNumber = i.PartNumber, Description = i.Descritpion.TrimEnd() };
I then have another SQL statement which returns the quantities on order and delivery date for each of those items. The Parts class has two other properties to store these. How do I update the existing Parts list with the other two values so that there is one Parts list with all four values?
UPDATE
The following code now brings out results.
var a = from a1 in db.usp_Optos_DaysOnHand_Report_PLC()
where a1.QTYGood == 0
orderby a1.PartNumber
select new Parts() { PartNumber = a1.PartNumber, Description = a1.Descritpion.TrimEnd() };
var b = from b1 in db.POP10110s
join b2 in db.IV00101s on b1.ITEMNMBR equals b2.ITEMNMBR
//from b3 in j1.DefaultIfEmpty()
where b1.POLNESTA == 2 && b1.QTYCANCE == 0
group b1 by new { itemNumber = b2.ITMGEDSC } into g
select new Parts() { PartNumber = g.Key.itemNumber.TrimEnd(), QtyOnOrder = g.Sum(x => Convert.ToInt32(x.QTYORDER)), DeliveryDue = g.Max(x => x.REQDATE).ToShortDateString() };
var joinedList = a.Join(b,
usp => usp.PartNumber,
oss => oss.PartNumber,
(usp, oss) =>
new Parts
{
PartNumber = usp.PartNumber,
Description = usp.Description,
QtyOnOrder = oss.QtyOnOrder,
DeliveryDue = oss.DeliveryDue
});
return joinedList.ToList();
Assuming your "other SQL statement" returns PartNumber, Quantity and DeliveryDate, you can join the lists into one:
var joinedList = q.Join(OtherSQLStatement(),
usp => usp.PartNumber,
oss => oss.PartNumber,
(usp, oss) =>
new Parts
{
PartNumber = usp.PartNumber,
Description = usp.Description,
Quantity = oss.Quantity,
DeliveryDate = oss.DeliveryDate
}).ToList();
You can actually combine the queries and do this in one join and projection:
var joinedList = doh.usp_Report_PLC().
Where(i => i.QTYGood == 0).
OrderBy(i => i.PartNumber).
Join(OtherSQLStatement(),
i => i.PartNumber,
o => o.PartNumber,
(i, o) =>
new Parts
{
PartNumber = i.PartNumber,
Description = i.Description,
Quantity = o.Quantity,
DeliveryDate = o.DeliveryDate
}).ToList();
And again: I assume you have PartNumber in both returned collections to identify which item belongs to which.
Edit
In this case the LINQ Query syntax would probably be more readable:
var joinedList = from aElem in a
join bElem in b
on aElem.PartNumber equals bElem.PartNumber into joinedAB
from abElem in joinedAB.DefaultIfEmpty()
select new Part
{
PartNumber = aElem.PartNumber,
Description = aElem.Description,
DeliveryDue = abElem == null ? null : abElem.DeliveryDue,
QtyOnOrder = abElem == null ? null : abElem.QtyOnOrder
};
Your DeliveryDue and QtyOnOrder are probably nullable. If not, replace the nulls by your default values. E.g. if you don't have the element in b and want QtyOnOrder to be 0 in the resulting list, change the line to
QtyOnOrder = abElem == null ? 0 : abElem.QtyOnOrder

Resources