is any way to optimize this solution?
whether there is any possibility of obtaining the same result by calling single query?
public List<Company> GetCompanies(DateTime maxDate, int stockQuotesCount)
{
List<Company> result = new List<Company>();
IList<Company> company = null;
DateTime lastSessionDate = new StockQuoteRepository().GetLastSessionDate(maxDate);
using (ISession s = DataAccessFacade.OpenSesion())
{
String sqlQuery = string.Empty;
sqlQuery = #"Select
*
From
dbo.Company c
Where
c.Company_FirstQuotationDate <= :date and
(c.Company_LastQuotationDate >= :date or c.Company_LastQuotationDate is Null)
Order By
c.Company_Name asc";
company = s.CreateSQLQuery(sqlQuery)
.AddEntity(typeof(Company))
.SetDateTime("date", lastSessionDate)
.List<Company>();
if (company != null)
{
for (int i = 0; i < company.Count; i++)
{
sqlQuery = #"Select
Top(:top)
*
From
dbo.StockQuote sq
Where
sq.StockQuote_Company_Id = :cId
and sq.StockQuote_Date <= :date
Order By
sq.StockQuote_Date desc";
company[i].StockQuotes = s.CreateSQLQuery(sqlQuery)
.AddEntity(typeof(StockQuote))
.SetParameter<int>("cId", company[i].Id)
.SetParameter<int>("top", stockQuotesCount)
.SetDateTime("date", lastSessionDate)
.List<StockQuote>();
}
}
}
return (List<Company>)company;
}
my fluent mapings:
public class CompanyMap : ClassMap<Company>
{
public CompanyMap()
{
this.Id(x => x.Id).Column("Company_Id");
this.Map(x => x.Name).Column("Company_Name");
this.Map(x => x.FirstQuotationDate).Column("Company_FirstQuotationDate");
this.Map(x => x.LastQuotationDate).Column("Company_LastQuotationDate");
this.HasMany(x => x.StockQuotes)
.Cascade.All()
.BatchSize(50)
.Inverse();
}
}
public class StockQuoteMap : ClassMap<StockQuote>
{
public StockQuoteMap()
{
this.Id(x => x.Id).Column("StockQuote_Id");
this.Map(x => x.Open).Column("StockQuote_Open");
this.Map(x => x.Low).Column("StockQuote_Low");
this.Map(x => x.High).Column("StockQuote_High");
this.Map(x => x.Close).Column("StockQuote_Close");
this.Map(x => x.Volume).Column("StockQuote_Volume");
this.Map(x => x.Date).Column("StockQuote_Date");
this.References(x => x.Company).Column("Company_Id");
}
}
ok, it is better query
using (ISession s = DataAccessFacade.OpenSesion())
{
String cHql = #"select
distinct c
from
Company c
join fetch c.StockQuotes s
where
c.FirstQuotationDate <= :maxDate and
(c.LastQuotationDate >= :maxDate or c.LastQuotationDate is Null)
and s.Date >= :minDate
order by
c.Name asc,
s.Date desc";
result = s.CreateQuery(cHql)
.SetDateTime("maxDate", lastSessionDate)
.SetDateTime("minDate", lastSessionDate.AddMonths(-2))
.List<Company>().ToList();
}
but there is one problem,
instead of giving time period for selecting StockQuote by StockQuote.Date form Company.StockQuotes, wants to make the TOP() on this joined collection
really, I only know maxDate (in this case), the calculation minDate is very difficult
Related
I have the following linq expression i was trying to convert string to Date and make a comparison as shown below but it gives the this error
Here is my Linq expression looks like
var ProjectList = Context.Project.AsNoTracking()
.Include(ca => ca.Cost)
.Where(p => p.Cost.Select(ca => DateTime.ParseExact(ca.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture)) <= request.ToDate && DateTime.ParseExact(ca.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture)) >= request.FromDate)
.ToListAsync();
I have the [MonthYYYYMM] in a database as a char type
[MonthYYYYMM] [char](8) NOT NULL,
How can i convert string to date and make the comparison?
Try this
var ProjectList = Context.Project.AsNoTracking()
.Include(ca => ca.Cost)
.Where(p => p.Cost.Select(ca => (DateTime.ParseExact(ca.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture))
<= request.ToDate) && (DateTime.ParseExact(ca.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture)) >= request.FromDate))
.ToListAsync();
() parenthesis around the expression you want to evaluate/compare.
my friend. Here is a sample. Hope to help :))
class Project
{
public List<Cost> Costs { get; set; }
}
class Cost
{
public string MonthYYYYMM { get; set; }
public double Price { get; set; }
}
var data = new List<Project>()
{
new Project()
{
Costs = new List<Cost>()
{
new Cost(){ MonthYYYYMM = "202007", Price = 10},
new Cost(){ MonthYYYYMM = "202008" , Price = 20},
new Cost(){ MonthYYYYMM = "202009" , Price = 30},
new Cost(){ MonthYYYYMM = "202010" , Price = 40}
}
}
};
var fromDate = DateTime.Now;
var endDate = DateTime.Now.AddMonths(1);
var projectList = data.Select(t=> new Project()
{
Costs = t.Costs.Where(c=>
DateTime.ParseExact(c.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture) >= fromDate
&& DateTime.ParseExact(c.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture) <= endDate) .ToList()
});
p.Cost.Select(ca => DateTime.ParseExact(ca.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture))
Select() return IEnumerable<DateTime>.That's main reason of error.
var ProjectList = Context.Project.AsNoTracking()
.Include(ca => ca.Cost)
.Where(ca => DateTime.ParseExact(ca.Cost.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture) <= request.ToDate && DateTime.ParseExact(ca.Cost.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture) >= request.FromDate)
.ToListAsync();
UPDATE
public class Cost
{
public int Id { get; set; }
public char[] MonthYYYYMM { get; set; }
public int projectId { get; set; }
public DateTime getDate() {
return DateTime.ParseExact(this.MonthYYYYMM, "yyyyMM", CultureInfo.InvariantCulture);
}
}
var ProjectList = Context.Project.AsNoTracking()
.Include(ca => ca.Cost)
.Where(
p => p.Cost.Any(c => c.getDate() <= ToDate && c.getDate() >= FromDate)
).ToListAsync();
It works.
I'm trying to convert this SQL Query into Core EF:
SELECT w.IdShippingBatch, w.BookingNumber, COUNT(c.IdShippingOrder) AS ShippingOrders, w.CreatedOn, w.ModifiedOn
FROM dbo.Shipping`enter code here`Batch AS w LEFT OUTER JOIN
dbo.ShippingOrders AS c ON w.IdShippingBatch = c.IdShippingBatch
WHERE (w.IdCompany = 2) AND (w.IdDealer = 1)
GROUP BY w.IdShippingBatch, w.BookingNumber, w.CreatedOn, w.ModifiedOn
I have tried multiple solutions, including several here. My latest attempt looks like:
var data = (from w in _context.ShippingBatch
join c in _context.ShippingOrders on w.IdShippingBatch equals c.IdShippingBatch into t1
where w.IdCompany == idCompany && w.IdDealer == idDealer
from t2 in t1.DefaultIfEmpty()
group t2 by new { w.IdShippingBatch, w.BookingNumber, w.CreatedOn, w.ModifiedOn } into t3
select new ShippingBatchDTO
{
IdShippingBatch = t3.Key.IdShippingBatch,
BookingNumber = t3.Key.BookingNumber,
ShippingOrders = t3.Count(),
CreatedOn = t3.Key.CreatedOn,
ModifiedOn = t3.Key.ModifiedOn
});
I have also tried adding t3.count(m => m.something != null), but that throws an error.
One major point of EF is to map the relationship between entities so that you can leverage LINQ and let EF compose an SQL query rather than trying to replace SQL with LINQ-QL.
If your ShippingBatch is mapped with a collection of ShippingOrders...
var batches = _context.ShippingBatch
.Where(x => x.IdCompany == idCompany && x.IdDealer == idDealer)
.Select(x => new ShippingBatchDTO
{
IdShippingBatch = x.IdShippingBatch,
BookingNumber = x.BookingNumber,
ShippingOrders = x.ShippingOrders.Count(),
CreatedOn = x.CreatedOn,
ModifiedOn = x.ModifiedOn
}).ToList();
If your ShippingBatch does not have a collection of ShippingOrders, but your ShippingOrder reference an optional ShippingBatch.
var batches = _context.ShippingOrder
.Where(x => x.ShippingBatch != null
&& x.ShippingBatch.IdCompany == idCompany
&& x.ShippingBatch.IdDealer == idDealer)
.GroupBy(x => x.ShippingBatch)
.Select(x => new ShippingBatchDTO
{
IdShippingBatch = x.Key.IdShippingBatch,
BookingNumber = x.Key.BookingNumber,
ShippingOrders = x.Count(),
CreatedOn = x.Key.CreatedOn,
ModifiedOn = x.Key.ModifiedOn
}).ToList();
That should hopefully get you moving in the right direction. If not, expand your question to include details of what you are seeing, and what you expect to see along with definitions for the applicable entities.
The code is working and returning a good list with (6) items.
However, we are seeing duplicates productSKU. We want to do a
DISTINCt productSKU.
pM = (from oo in ctx.option1
where mArray.Contains(oo.option1Code)
select oo)
.Select(o => new ProductMatch
{
productSKU = o.option1Code,
productPrice = o.price,
option1Desc = o.option1Desc
}).ToList();
I have tried to add Distinct() after the Lambda but I still get (6) items.
I am also getting error when I add GroupBy(...) "Cannot convert lambda expression to type 'string' because it is not a delegate type"
Try this syntax:
pM = (from o in ctx.option1
where mArray.Contains(o.option1Code)
let t = new
{
productSKU = o.option1Code,
productPrice = o.price,
option1Desc = o.option1Desc
}
group o by t into grp
select new ProductMatch
{
productSKU = grp.Key.option1Code,
productPrice = grp.Key.price,
option1Desc = grp.Key.option1Desc
}).ToList();
When you use a Distinct on a lamba expression, the Distinct only looks at the EntityKey for the distinct comparision. You will need to implement your own IEqualityComparer for your select.
internal class UniqueProductComparer : IEqualityComparer<ProductMatch>
{
public bool Equals(ProductMatch x, ProductMatch y)
{
if(Object.ReferenceEquals(x,y)) return true;
if(Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y,null))
return false;
return x.productSKU == y.ProductSKU && x.productPrice == y.productPrice && x.option1Desc == y.option1Desc;
}
public int GetHashCode(ProductMatch match)
{
if (Object.ReferenceEquals(match,null)) return 0;
return match.productSKU.GetHashChode() + match.productPrice.GetHashCode() + match.option1Desc.GetHashCode();
}
}
Then in your lamba, change it to this:
pM = (from oo in ctx.option1
where mArray.Contains(oo.option1Code)
select oo)
.Select(o => new ProductMatch
{
productSKU = o.option1Code,
productPrice = o.price,
option1Desc = o.option1Desc
}).Distinct(new UniqueProductComparer()).ToList();
A slight variation of IAbstractDownvoteFactor's answer
pM = (from oo in ctx.option1
where mArray.Contains(oo.option1Code)
select oo)
.GroupBy(o => o.option1Code)
.Select(g => g.First())
.Select(o => new ProductMatch
{
productSKU = o.option1Code,
productPrice = o.price,
option1Desc = o.option1Desc
}).ToList();
Alternatively, if you use linq heavily and are open to using libraries, there is morelinq that gives you DistinctBy() extension and several other useful extensions.
ICustomerRepository define: Customer GetCustomerByID(int CustomerID);
//Arrange
var customers = new Customer()
{
new Customer() { CustomerID = 1, Name = "Richard" },
new Customer() { CustomerID = 2, Name = "Evan" },
new Customer() { CustomerID = 3, Name = "Marie-France" },
}.AsQueryable();
Mock<ICustomerRepository> mock = new Mock<ICustomerRepository>();
How do I tell Moq to return the correct customer depending on the CustomerID paremeter???
I've been able to set up the first part, but not the return object.
mock.Setup(m => m.GetCustomerByID(It.Is<int>(i => i >= 0))).Returns(/// To be define///)
The Idea is to have the same result as this:
public Customer GetCustomerByID(int CustomerID)
{
return customers.FirstOrDefault(c => c.CustomerID == CustomerID);
}
Thanks for helping
mock.Setup(x => x.GetCustomerByID(It.IsAny<int>()))
.Returns((int id) =>
customers.FirstOrDefault(c => c.CustomerID == id));
Just make customers a List<Customer> - no need for AsQueryable.
I having a trouble with a query
I need to take out the SHIPMENT from GetAllOrderData - the same place where you can find POD_DATE and RECEIVE_NAME...but I get an error
Error 1 The name 'x' does not exist in the current context
My code is:
public IEnumerable<ReportItemDTO> GetTaskProgress(DateTime targetDate)
{
try
{
var startDate = targetDate.Date;
var endDate = startDate.AddDays(1);
OrderDataRepository rep = new OrderDataRepository();
var query = rep.GetAllOrderData()
.Where(x => x.POD_DATE >= startDate && x.POD_DATE <= endDate)
.GroupBy(o => o.User)
.Select(g => new ReportItemDTO
{
DriverId = g.Key.Id,
PdriverName = g.Key.Name,
OrderCount = g.Count(),
ReportedOrdersCount = g.Count(o => o.RECEIVE_NAME != null),
SHIPMENT = (x.SHIPMENT)
} );
return query;
SHIPMENT = (x.SHIPMENT)
Well you are within a grouping when you try to make that assignment - there are many shipments in each grouping not just one - in fact all shipments for that particular user. Assuming you want a collection of them you could do:
Shipments = g.Select( x=> x.SHIPMENT)
Edit:
If you just want the first shipment for each user (somewhat illogical but fits your data model):
SHIPMENT = g.Select( x=> x.SHIPMENT).First()