Method not returning items within specified timespan - c#

Trying to figure out why this method isn't returning the items within the timespan I specified with some DateTime variables. I do get a result but it makes no sense and provide incorrect values.
The method is supposed to return all bestsellers from yesterday (the past 24 hours). However it seems that the method returns all bestsellers that have been sold since the beginning. In the Database there's a column called "CreatedOnUtc" wich provide a date, guess this could be used as a date to test but i don't know how to access it as it's in another class.
public IList<BestsellersReportLine> DailyBestsellersReport()
{
int recordsToReturn = 5; int orderBy = 1; int groupBy = 1;
var yesterDay = DateTime.Now.Subtract(new TimeSpan(1, 0, 0, 0));
var earliest = new DateTime(yesterDay.Year, yesterDay.Month, yesterDay.Day, 0, 0, 0);
var latest = earliest.Add(new TimeSpan(1, 0, 0, 0, -1));
var currentDay = DateTime.Now;
var dayBefore = DateTime.Now.AddDays(-1);
var query1 = from opv in _opvRepository.Table
where earliest <= currentDay && latest >= dayBefore
join o in _orderRepository.Table on opv.OrderId equals o.Id
join pv in _productVariantRepository.Table on opv.ProductVariantId equals pv.Id
join p in _productRepository.Table on pv.ProductId equals p.Id
select opv;
var query2 = groupBy == 1 ?
//group by product variants
from opv in query1
where earliest <= currentDay && latest >= dayBefore
group opv by opv.ProductVariantId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
:
//group by products
from opv in query1
where earliest <= currentDay && latest >= dayBefore
group opv by opv.ProductVariant.ProductId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
;
switch (orderBy)
{
case 1:
{
query2 = query2.OrderByDescending(x => x.TotalQuantity);
}
break;
case 2:
{
query2 = query2.OrderByDescending(x => x.TotalAmount);
}
break;
default:
throw new ArgumentException("Wrong orderBy parameter", "orderBy");
}
if (recordsToReturn != 0 && recordsToReturn != int.MaxValue)
query2 = query2.Take(recordsToReturn);
var result = query2.ToList().Select(x =>
{
var reportLine = new BestsellersReportLine()
{
EntityId = x.EntityId,
TotalAmount = x.TotalAmount,
TotalQuantity = x.TotalQuantity
};
return reportLine;
}).ToList();
return result;
}
There is a similar method wich has specified startTime and endTime, i believe it searches the database within a time record. Allthough this method is displayed in a view with choosable startDate/endDate in textboxes. However i need the time record for DailyBestsellersReport to be specified in the code as this will be a process running in the background.
Here is a similar period with DateTime parameteers:
public virtual IList<BestsellersReportLine> BestSellersReport(DateTime? startTime,
DateTime? endTime,int recordsToReturn = 5, int orderBy = 1, int groupBy = 1)
{
some code...
}
Any thoughts?

where earliest <= currentDay && latest >= dayBefore
It's useless condition, it's allways true.
You need test for some 'time' fields from DB, if u want to filter your db records.
Update
I suposed, that you have OrderDate column in _orderRepository.Table
than you snippet can be transformed into something like bellow:
var currentTime = DateTime.Now;
var today = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, 0, 0, 0);
var yesterDay = today.Subtract(new TimeSpan(1, 0, 0, 0));
//suppose, that we gather all data for yesterday
var query1 = from opv in _opvRepository.Table
join o in _orderRepository.Table on opv.OrderId equals o.Id
join pv in _productVariantRepository.Table on opv.ProductVariantId equals pv.Id
join p in _productRepository.Table on pv.ProductId equals p.Id
where yesterDay <= o.OrderDate && today >= o.OrderDate
select opv;
var query2 = groupBy == 1 ?
//group by product variants
from opv in query1
group opv by opv.ProductVariantId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
:
//group by products
from opv in query1
group opv by opv.ProductVariant.ProductId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
;

Related

Split a string value in list using linq

I have a list with a column value like "0000000385242160714132019116002239344.ACK" i need to take last 6 digits from this value like "239344" without extension(.ack) when binding to the list.
And i need to find the sum of Salary field also.
My query looks like below.
var result = from p in Context.A
join e in B on p.Id equals e.Id
join j in Context.C on e.CId equals j.CId
where (e.Date >= periodFrom && e.Date <= periodTo)
group new
{
e,
j
} by new
{
j.J_Id,
e.Date,
e.Es_Id,
e.FileName,
j.Name,
e.ACK_FileName,
p.EmpSalaryId,
p.Salary
} into g
orderby g.Key.CId, g.Key.Es_Id, g.Key.Date, g.Key.FileName
select new
{
CorporateId = g.Key.CId,
ProcessedDate = g.Key.Date,
EstID = g.Key.Es_Id,
FileName = g.Key.FileName,
Name = g.Key.Name,
ack = g.Key.ACK_FileName,
EmpSalaryId = g.Key.EmpSalaryId,
Salary=g.Key.Salary
};
var Abc=result.ToList();
var result = (from p in Context.A
join e in B on p.Id equals e.Id
join j in Context.C on e.CId equals j.CId
where (e.Date >= periodFrom && e.Date <= periodTo)
group new { e, j } by new
{
j.J_Id,
e.Date,
e.Es_Id,
e.FileName,
j.Name,
ACK_FileName = e.ACK_FileName.Substring(e.ACK_FileName.IndexOf(".ACK") - 7, 11),
p.EmpSalaryId,
p.Salary
} into g
orderby g.Key.CId, g.Key.Es_Id, g.Key.Date, g.Key.FileName
select new
{
CorporateId = g.Key.CId,
ProcessedDate = g.Key.Date,
EstID = g.Key.Es_Id,
FileName = g.Key.FileName,
Name = g.Key.Name,
ack = g.Key.ACK_FileName,
EmpSalaryId = g.Key.EmpSalaryId,
Salary = g.Sum(item => item.Salary)
}).ToList();

Adding a custom task in NopCommerce, return list of daily bestsellers

I'm working on creating a custom task in NopCommerce that lists most sold products of the day and show this data in the admin panel. E g lists all products that has been sold and order them by number of sold.
Iv'e found some code that runs a BestSeller report which is great, allthough this method is quite large and i'm uncertain which part i actually need in order to display the list of bestsellers. Also the method for bestsellers is a "virtual IList and the execute method is void.
This is the code for bestsellers:
class MostSoldProductsTask : ITask
{
private readonly IRepository<Order> _orderRepository;
private readonly IRepository<OrderProductVariant> _opvRepository;
private readonly IRepository<Product> _productRepository;
private readonly IRepository<ProductVariant> _productVariantRepository;
private readonly IDateTimeHelper _dateTimeHelper;
private readonly IProductService _productService;
public virtual IList<BestsellersReportLine> BestSellersReport(DateTime? startTime,
DateTime? endTime, OrderStatus? os, PaymentStatus? ps, ShippingStatus? ss,
int billingCountryId = 0,
int recordsToReturn = 5, int orderBy = 1, int groupBy = 1, bool showHidden = false)
{
int? orderStatusId = null;
if (os.HasValue)
orderStatusId = (int)os.Value;
int? paymentStatusId = null;
if (ps.HasValue)
paymentStatusId = (int)ps.Value;
int? shippingStatusId = null;
if (ss.HasValue)
shippingStatusId = (int)ss.Value;
var query1 = from opv in _opvRepository.Table
join o in _orderRepository.Table on opv.OrderId equals o.Id
join pv in _productVariantRepository.Table on opv.ProductVariantId equals pv.Id
join p in _productRepository.Table on pv.ProductId equals p.Id
where (!startTime.HasValue || startTime.Value <= o.CreatedOnUtc) &&
(!endTime.HasValue || endTime.Value >= o.CreatedOnUtc) &&
(!orderStatusId.HasValue || orderStatusId == o.OrderStatusId) &&
(!paymentStatusId.HasValue || paymentStatusId == o.PaymentStatusId) &&
(!shippingStatusId.HasValue || shippingStatusId == o.ShippingStatusId) &&
(!o.Deleted) &&
(!p.Deleted) &&
(!pv.Deleted) &&
(billingCountryId == 0 || o.BillingAddress.CountryId == billingCountryId) &&
(showHidden || p.Published) &&
(showHidden || pv.Published)
select opv;
var query2 = groupBy == 1 ?
//group by product variants
from opv in query1
group opv by opv.ProductVariantId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
:
//group by products
from opv in query1
group opv by opv.ProductVariant.ProductId into g
select new
{
EntityId = g.Key,
TotalAmount = g.Sum(x => x.PriceExclTax),
TotalQuantity = g.Sum(x => x.Quantity),
}
;
switch (orderBy)
{
case 1:
{
query2 = query2.OrderByDescending(x => x.TotalQuantity);
}
break;
case 2:
{
query2 = query2.OrderByDescending(x => x.TotalAmount);
}
break;
default:
throw new ArgumentException("Wrong orderBy parameter", "orderBy");
}
if (recordsToReturn != 0 && recordsToReturn != int.MaxValue)
query2 = query2.Take(recordsToReturn);
var result = query2.ToList().Select(x =>
{
var reportLine = new BestsellersReportLine()
{
EntityId = x.EntityId,
TotalAmount = x.TotalAmount,
TotalQuantity = x.TotalQuantity
};
return reportLine;
}).ToList();
return result;
}
public void Execute()
{
throw new NotImplementedException("Return something");
}
I also have to return this list via the "Execute" -method that is implementing the ITask interface. My best guess is to have one method creating the list of bestsellers and have have the "Execute method implementing the first one and return it.
Thank you
I believe you misunderstood the purpose if ITask interface. ITask is used to run some background, non-UI tasks, so you can never get it to 'return' the list in admin panel.
What you want to do, instead, is to run it periodically and save the data in some custom table. Then use it

Populate list using LINQ

I have an ArrayList of type RawResults where RawResults is a location and a date
public class RawResult
{
public string location { get; set; }
public DateTime createDate {get; set; }
public RawResults(string l, DateTime d)
{
this.location = l;
this.createDate = d;
}
}
I would like to use LINQ to populate a list containing each distinct location and the number of times it appears in my arraylist. If I able to do it in SQL it would look like this
select
bw.location,
count(*) as Count
from
bandwidth bw,
media_log ml
where
bw.IP_SUBNET = ml.SUBNET
group by bw.location
order by location asc
later I will also have to do the same thing, but within a given date range.
UPDATE
this is the query that was run to get all of the data in rawData
SELECT
MEDIASTREAM.BANDWIDTH.LOCATION, MEDIASTREAM.MEDIA_LOG.CREATE_DATE
FROM
MEDIASTREAM.BANDWIDTH INNER JOIN
MEDIASTREAM.MEDIA_LOG ON MEDIASTREAM.BANDWIDTH.IP_SUBNET =
MEDIASTREAM.MEDIA_LOG.SUBNET
Now I need to query the data that was returned in rawData to get different result sets. I have available a List to query.
You can do this:
var results =
(from bw in data.bandwith
join ml in data.media_log on bw.IP_SUBNET equals ml.SUBNET
group bw by bw.location into g
orderby g.Key
select new
{
location = g.Key,
Count = g.Count()
})
.ToList();
Although the ToList is not necessary unless you absolutely need it to be a List<T>. To filter by time, you can just do something like this:
var results =
(from bw in data.bandwith
join ml in data.media_log on bw.IP_SUBNET equals ml.SUBNET
where bw.createDate >= minDate && bw.createDate <= maxDate
group bw by bw.location into g
orderby g.Key
select new
{
location = g.Key,
Count = g.Count()
})
.ToList();
If media_log isn't relevant, you can just omit the join:
var results =
from bw in data.bandwith
group bw by bw.location into g
orderby g.Key
select new
{
location = g.Key,
Count = g.Count()
}
Or in fluent syntax:
var results = data.bandwith
.GroupBy(bw => bw.location, (k, g) => new { location = k, Count = g.Count() })
.OrderBy(r => r.location);
To filter by date, just use this:
var results =
from bw in data.bandwith
where bw.createDate >= minDate && bw.createDate <= maxDate
group bw by bw.location into g
orderby g.Key
select new
{
location = g.Key,
Count = g.Count()
};
Or in fluent syntax:
var results = data.bandwith
.Where(bw => bw.createDate >= minDate && bw.createDate <= maxDate)
.GroupBy(bw => bw.location, (k, g) => new { location = k, Count = g.Count() })
.OrderBy(r => r.location);
Note, to use an ArrayList, or any other non-generic collection type in a Linq query, use the Cast<T> or OfType<T> methods, like this:
var results = bandwithArrayList
.Cast<RawResults>()
.GroupBy(bw => bw.location, (k, g) => new { location = k, Count = g.Count() })
.ToList();
List<RawResult> results = MethodToGetResults();
var locationCount = results
.GroupBy(r => r.location)
.Select(lc => new {Location = lc.location, Count = lc.Count()});

LINQ query to group records by month within a period

I am looking for some help on adapting the following LINQ query to return all dates within the next 6 months, even those where no records fall within the given month.
var maxDate = DateTime.Now.AddMonths(6);
var orders = (from ord in db.Items
where (ord.Expiry >= DateTime.Now && ord.Expiry <= maxDate)
group ord by new
{
ord.Expiry.Value.Year,
ord.Expiry.Value.Month
}
into g
select new ExpiriesOwnedModel
{
Month = g.Select(n => n.Expiry.Value.Month).First(),
Quantity = g.Count()
}).ToList();
I'd really appreciate any assistance or pointers on how best to implement this.
I'm not sure how well it'll interact with your database, but I'd do this as with a join:
var firstDaysOfMonths = Enumerable.Range(0, 7).Select(i =>
new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(i));
var orders = firstDaysOfMonths.GroupJoin(
db.Items,
fd => fd,
ord => new DateTime(ord.Expiry.Value.Year, ord.Expiry.Value.Month, 1),
(fd, ords) => new { Month = fd.Month, Quantity = ords.Count() });
Note you may end up with an extra month where before you didn't (on the first day of the month?)
Stolen from Rawling's answer, if you prefer query syntax for group joins (I do):
var orders =
from month in Enumerable.Range(0, 7)
.Select(i => new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(i))
join ord in db.Items
on month equals new DateTime(ord.Expiry.Value.Year, ord.Expiry.Value.Month, 1)
into ords
select new { month.Month, Quantity = ords.Count() };
Alternative if it does not play nice with the database:
var rawGroups = db.Items.Where(item.Expiry >= DateTime.Now && ord.Expiry <= maxDate)
.GroupBy(item => new
{
item.Expiry.Value.Year,
item.Expiry.Value.Month
}, g => new ExpiriesOwnedModel()
{
Month = g.Key.Month,
Quantity = g.Count()
}).ToDictionary(model => model.Month);
var result = Enumerable.Range(DateTime.Now.Month,6)
.Select(i => i > 12 ? i - 12 , i)
.Select(i => rawGroups.Keys.Contains(i) ?
rawGroups[i] :
new ExpiriesOwnedModel()
{ Month = i , Quantity = 0 });

LINQ Query with both CASE statement and SUM function

I'm struggling to find an example of how to return a conditional sum using a LINQ query or LAMBDA. I've written both independently but combining the CASE with SUM is vexing. I'm tempted to "cheat" and use a SQL view, but thought I'd ask first. I greatly appreciate any suggestions. Here's my SQL that I'm looking to convert.
SELECT p.product_name,
SUM(CASE WHEN o.order_dt <= getdate() - 1 THEN o.quantity END) AS volume_1day,
SUM(CASE WHEN o.order_dt <= getdate() - 7 THEN o.quantity END) AS volume_7day,
SUM(CASE WHEN o.order_dt <= getdate() - 30 THEN o.quantity END) AS volume_30day,
SUM(o.quantity) AS volume_all
FROM products p left outer join orders o on p.product_id = o.product_id
GROUP BY p.product_name
Here is an example using the Northwinds database. This will get you the results that you are expecting but the SQL won't match your example.
using (var context = new NorthwindEntities())
{
DateTime volumn1Date = DateTime.Today.AddDays(-1);
DateTime volumn7Date = DateTime.Today.AddDays(-7);
DateTime volumn30Date = DateTime.Today.AddDays(-30);
var query = from o in context.Order_Details
group o by o.Product.ProductName into g
select new
{
ProductName = g.Key,
Volume1Day = g.Where(d => d.Order.OrderDate.Value <= volumn1Date)
// cast to Int32? because if no records are found the result will be a null
.Sum(d => (Int32?) d.Quantity),
Volume7Day = g.Where(d => d.Order.OrderDate.Value <= volumn7Date)
.Sum(d => (Int32?) d.Quantity),
Volume30Day = g.Where(d => d.Order.OrderDate.Value <= volumn30Date)
.Sum(d => (Int32?) d.Quantity)
};
var list = query.ToList();
}
answer does not wrong but does not generate optimize query. better answer is:
using (var context = new NorthwindEntities())
{
DateTime volumn1Date = DateTime.Today.AddDays(-1);
DateTime volumn7Date = DateTime.Today.AddDays(-7);
DateTime volumn30Date = DateTime.Today.AddDays(-30);
var query = from o in context.Order_Details
group o by o.Product.ProductName into g
select new
{
ProductName = g.Key,
Volume1Day = g.Sum(d => d.Order.OrderDate.Value <= volumn1Date ? (Int32?) d.Quantity : 0),
Volume7Day = g.Sum(d => d.Order.OrderDate.Value <= volumn7Date ? (Int32?) d.Quantity : 0),
Volume30Day = g.Sum(d => d.Order.OrderDate.Value <= volumn30Date ? (Int32?) d.Quantity : 0)
};
var list = query.ToList();
}

Categories

Resources