I have 3 tables. Order, Orderlines and Stores. In Order table has StoreId which is a foreign key from Stores table and In Orderlines table has OrderId a foreign key from Order table. I only need to get the fields Order.OrderId, Order.WarehouseOrderId, Store.StoreName and the count of Orderlines per Order. So currently this is my implementation:
public List<Order> GetOrdersDashboardWithoutStatus1(SearchDashboardCriteria cri)
{
using (var ctx = CreateDbContext())
{
var orders = (from items in ctx.Orders select items);
if (cri.MerchantId != 0)
{
orders = orders.Where(x => x.Store.MerchantId == cri.MerchantId);
}
return orders.Where(x => (DbFunctions.TruncateTime(x.DateImported) >= DbFunctions.TruncateTime(cri.StartDate))
&& (DbFunctions.TruncateTime(x.DateImported) <= DbFunctions.TruncateTime(cri.EndDate)))
.Include(x => x.Store).Include(x => x.OrderLines).ToList();
}
}
Through the currently implementation is working but the performance is very slow and sometimes it gets a Time Out error because a records may have 30K+ orders.
You could try something like this
using (var ctx = CreateDbContext())
{
var orders = (from x in ctx.Orders
where x.Store.MerchantId == cri.MerchantId
&& add your other where condition
select NewDataModel
{
orderId = x.OrderId,
wareHouse = x.WarehouseOrderId,
storeName = x.Store.StoreName
}).ToArray();
}
Anonymous projection or projection to your custom model only retrieve columns that are included in the projection.
Instead of Select * from Orders ... it will be Select OrderId,WareHouseOrderId from Orders
you can also try for paging (Take,skip) if your use case support it.
Similar answer for anonymous projection
Related
I have created two tables: Claim and ClaimAttachments.
I'm trying to join them on ClaimID in order to get the filtered data from both the tables.
public ActionResult Index(int? search)
{
if (search!=null)
{
var Product = (from P in db.Claims
join C in db.ClaimAttachments on
P.ClaimID equals C.ClaimID
select new Claim
{
ClaimID = P.ClaimID,
ClaimBatchID = P.ClaimBatchID,
PatientControlNumber = P.PatientControlNumber,
PatientFirstName = P.PatientFirstName,
PatientLastName = P.PatientLastName,
ServiceFromDate = P.ServiceFromDate,
ServiceToDate = P.ServiceToDate,
});
return View(db.Claims.Where(x => x.ClaimID == search).ToList());
}
else
{
return View(db.Claims.ToList());
}
I'm able to get the searched result but from single table. The join is not working.
Currently you're only selecting from the Claims data:
return View(db.Claims.Where(x => x.ClaimID == search).ToList());
You have a join query just above that line of code:
var Product = (from P in db.Claims
join C in db.ClaimAttachments on
P.ClaimID equals C.ClaimID
select new Claim
{
ClaimID = P.ClaimID,
ClaimBatchID = P.ClaimBatchID,
PatientControlNumber = P.PatientControlNumber,
PatientFirstName = P.PatientFirstName,
PatientLastName = P.PatientLastName,
ServiceFromDate = P.ServiceFromDate,
ServiceToDate = P.ServiceToDate
});
But you don't do anything with the results of that query. It sounds like you meant to use the results of that query (which is in the Product variable, which incidentally should probably have a plural name since it's a collection) instead of just selecting from db.Claims. Something like this:
return View(Product.Where(x => x.ClaimID == search).ToList());
Note however that you're still only selecting data from one table. Though the join operation may alter the results of that selection. But the selection itself is here:
select new Claim
{
ClaimID = P.ClaimID,
ClaimBatchID = P.ClaimBatchID,
PatientControlNumber = P.PatientControlNumber,
PatientFirstName = P.PatientFirstName,
PatientLastName = P.PatientLastName,
ServiceFromDate = P.ServiceFromDate,
ServiceToDate = P.ServiceToDate
}
Notice how every value selected is from the P alias, which is defined here:
from P in db.Claims
So you're successfully joining the two tables, but only selecting data from one of the two tables. If you want to also select data from the other table then, well, you need to select data from the other table. For example, if there's a property on that table called SomeProperty that you want to select then you'd need to select it, and into an object which has that property.
For example, you might create a view model (let's call it ClaimViewModel as an example) which represents a combined record of the two tables, containing the properties you want from each. Then you'd select into that type:
select new ClaimViewModel
{
ClaimID = P.ClaimID,
ClaimBatchID = P.ClaimBatchID,
PatientControlNumber = P.PatientControlNumber,
PatientFirstName = P.PatientFirstName,
PatientLastName = P.PatientLastName,
ServiceFromDate = P.ServiceFromDate,
ServiceToDate = P.ServiceToDate,
SomeProperty = C.SomeProperty // <--- here
}
This would select the combined data into a list of ClaimViewModel objects, which you'd then filter based on your "search" and return to your view just like you do with the Claims objects now. And of course that view would need to be updated to expect a collection of ClaimViewModel objects instead of a collection of Claim objects.
How can I achieve a join and a where in C# MVC using something like Linq or EF Join?
This is the equivalent SQL I am trying to achieve.
select * from promotion P
JOIN PromotionsClaimed PC
on PC.PromotionId = P.objectid
where PC.userId = #USERID
This method should return a list of the promotions for the user. First, I get a list of all of the promotions, then I get the composite list of claimed promotions for the user. This is what I have so far.
public IList<Promotion> GetRewardsForUser(string userId)
{
//a list of all available promotions
IList<Promotion> promos = _promotionLogic.Retrieve();
//contains a list of Promotion.objectIds for that user
IList<PromotionsClaimed> promosClaimed = _promotionsClaimedLogic.RetrieveByCriteria(t => t.userId == userId);
//should return a list of the Promotion name and code for the rewards claimed by user, but a complete list of Promotion entities would be fine
var selectedPromos =
from promo in promos
join promoClaimed in promosClaimed on promo.objectId equals promoClaimed.PromotionId
select new { PromoName = promo.Name, PromoCode = promo.Code };
return selectedPromos;
}
I realize there are a lot of problems here. I'm trying to learn Linq and Entity Framework, but I don't know how to add the where clause to an IList or if there is an easier way to accomplish this.
It seems to me like there would be a way to filter the promotion list where it contains the Promotion.objectId in the promosClaimed list, but I don't know the syntax.
public IList<Promotion> GetRewardsForUser(string userId)
{
//a list of all available promotions
IList<Promotion> promos = _promotionLogic.Retrieve();
//contains a list of Promotion.objectIds for that user
IList<PromotionsClaimed> promosClaimed = _promotionsClaimedLogic.RetrieveByCriteria(t => t.userId == userId);
//should return a list of the Promotion name and code for the rewards claimed by user, but a complete list of Promotion entities would be fine
var selectedPromos =
(from promo in promos
join promoClaimed in promosClaimed on promo.objectId equals promoClaimed.PromotionId
select new { PromoName = promo.Name, PromoCode = promo.Code }).ToList();
return selectedPromos;
}
If I understood your question correctly, you could do something like this:
public IList<Promotion> GetRewardsForUser(string userId)
{
//contains a list of Promotion.objectIds for that user
IList<PromotionsClaimed> promosClaimed = _promotionsClaimedLogic
.RetrieveByCriteria(t => t.userId == userId);
var promotionIds = promosClaimed.Select(p => p.PromotionId).ToList();
IList<Promotion> promos = _promotionLogic.Retrieve()
.Where(p => promotionIds.Contains(p.objectId))
.Select(p => new { PromoName = p.Name, PromoCode = p.Code });
return selectedPromos;
}
The claimed promotions should be already filtered by a user so this should possibly work.
First of all, you're using entity framework? Or are you just trying to do join of two collections?
Because if you are using EF, you're thinking the wrong way. In the entity the proper way is to use include, for example:
public DbSet<promotion > promotion { get; set; }
public DbSet<PromotionsClaimed> PromotionsClaimed{ get; set; }
Context.promotion.Include(o => o.PromotionsClaimed).FirstOrDefault(s => s.Id == USERID);
If you need only join two collection using linq, you can do that.
var userId = 1;
var test =
(
from p in promos
join pc in promosClaimed on p.objectid equals pc.PromotionId
where pc.userId == userId
select p
).ToList();
Have you tried just to add your condition to your code? Like:
var selectedPromos =
from promo in promos
join promoClaimed in promosClaimed on promo.objectId equals promoClaimed.PromotionId
where promosClaimed.UserId == userId
select new { PromoName = promo.Name, PromoCode = promo.Code };
That should work or I just didn't understand you
How do you suppose I tackle this? Basically, I have this inital query:
var orders = (from order in _dbContext.Orders
join orderDetail in _dbContext.OrderDetails on order.ID equals orderDetail.OrderID
where order.StoreID == storeID
select new Order
{
ID = order.ID,
No = order.ID,
Type = "", // Notice that this is empty; this one needs updating
Quantity = order.Quantity,
// more properties here
}).AsQueryable();
After this query, I need to loop through the result and update the Type property based on different criteria like this:
string type = "";
foreach (OrderDetailDto order in orders)
{
if (order.UserID != null)
type = "UserOrder";
else if (order.UserID == null)
type = "NonUserOrder";
else if (order.Cook == null && (order.Option == "fiery"))
type = "FieryCook";
else if (check if this has corresponding records in another table) // this part I don't know how to effectively tackle
type = "XXX";
// Update.
order.Type = type;
}
The problem is one of my criteria needs me to check if there are existing record in the database. I would use JOIN but if I have to loop thru several hundreds or thousands of records and then JOIN each one of them then check on db just to get one value, I think that would be very slow.
I can't do the JOIN on the initial query because I might do a different JOIN based on a different criterion. Any ideas?
You could just join all the lookup tables you might possibly need in left join type way:
from o in Orders
from c in Cooks.Where(x => x.OrderId == m.OrderId).DefaultIfEmpty()
from u in Users.Where(x => x.OrderId == o.OrderId).DefaultIfEmpty()
select new
{
Order = m,
Cook = c,
User = u
}
or depending on your usage patterns you could build the required tables into local Lookups or Dictionaries for linear time searching thereafter:
var userDict = Users.ToDictionary(x => x.UserId);
var userIdDict = Users.Select(x => x.UserId).ToDictionary(x => x);
var cooksLookup = Cooks.ToLookup(x => x.Salary);
I have Oracle db with EF 5 on top of it.
Lets say I have tables Company and Orders. I have EF corresponding entities where Company has field
List<Orders> Orders.
I dont want to create an association.
I have a query which is IQuerable and I need to fill the Orders for each company using
order.CompanyId == company.Id
I cant wrap my head around this atm.. Any help will be appreciated.
EDIT: not every company has orders. The orders list could be empty.
I would consider using the .Join() method to include the Orders table. I write this from memory, so please forgive syntax errors.
//I only use this bc I don't know the full schema.
class DTOCompany {
public int ID {get;set;}
public List<Orders> Orders {get;set;}
}
public List<Companies> GetCompaniesOrders() {
using (var db = new Entities()) {
return db.Companies
.AsEnumerable() //may not be needed.
.Join(db.Orders,
c => CompanyId,
o => o.CompanyId,
(c,o) => new { Company = c, Orders = o})
)
.Select(co => new DTOCompany() {
ID = co.Companies.CompanyId,
Orders = co.Orders.ToList()
})
.ToList();
}
}
I'm trying to retrieve a List<Student> from my database.
Basically, the schema is:
GradeParalelo ---- GradeStudent ---- Student
Where the GradeStudent table holds primary keys for GradeParalelo and Student. NOTE: The GradeStudent table has an extra column to hold an integer. This is not just an association table.
Here's what I've tried so far:
ColegioDBV2Entities db = new ColegioDBV2Entities();
public List<Student> FindAllStudentsFromGradeParalelo(int gradeParaleloId)
{
return (db.Students
.Include("GradeStudents")
.Include("GradeStudents.GradeParalelo")
.Where<Student>(s => s.StudentId == gradeParaleloId)).ToList();
}
But it's retrieving a single student for every gradeParalelo I choose. Understandably, because I'm comparing a StudentId with a GradeParaleloId. This is not what I want.
Can anyone suggest a way to retrieve this collection?
Image that I want to retrieve all students that are in the GradeStudent table with GradeParalelo ID 6.
Basically this, in a more elegant form:
public List<Student> FindAllStudentsFromGradeParalelo(int gradeParaleloId)
{
List<Student> students = new List<Student>();
using(GradeStudentRepository repo = new GradeStudentRepository())
{
var items = repo.FindAllGradeStudents().Where(g => g.GradeParaleloId == gradeParaleloId);
StudentRepository studentRepo = new StudentRepository();
foreach (var o in items)
{
students.Add(studentRepo.FindStudent(o.StudentId));
}
}
return students;
}
How about
return db.GradeParaleloes.Single(g => g.GradeParaleloId == gradeParaleloId)
.GradeStudents.Select(s => s.Student).ToList();
that is a simple query as:
return
db.Students
.Where( x => x.GradeParalelo.gradeParaleloId == gradeParaleloId )
.ToList();
if you have the FK right, you just need to call the FK and internally it will link all the needed tables.