I have 3 tables Purchase, PurchaseBill, and PurchasePayment.
Purchase has one-to-many relationship with PurchaseBill
PurchaseBill has one-to-many relationship with PurchasePayment
I'm looking for a Linq (fluent) equivalent of this SQL Query
SELECT COUNT('') FROM PurchasePayment
WHERE PurchaseBillId IN (
SELECT PurchaseBillId FROM PurchaseBill WHERE PurchaseId = #PurchaseId
)
Basically I want to know if any PurchasePayment record exist for certain #PurchaseId
Currently I'm using
var bills = _context.PurchaseBill.Where(a => a.PurchaseId == obj.Id);
foreach (var bill in bills)
{
var hasPayment = _context.PurchasePayment.Any(a => a.PurchaseBillId == bill.Id);
if (hasPayment)
ctx.AddFailure("Cannot modify paid Purchase.");
}
I tried
var hasPayment = _context.PurchasePayment.Any(w => bills.Contains(w.PurchaseBillId));
but it's not working. Is it possible to do it without looping in Linq?
I agree with Gert; you ought to have a PurchaseBill class with an ICollection<PurchasePayment> PurchasePayments property (linking onto the multiple payments) and an int PurchaseId property (linking back to a single purchase) and be able to do something like:
var hasPayment = context.PurchaseBills.Any(
pb => pb.PurchaseId == obj.Id && pb.PurchasePayments.Any()
);
"Is there any purchasebill with PurchaseId blahblah and any PurchasePayment?"
Or, if you plan to do something with each bill, and its payments, something like:
var bills = context.PurchaseBills.Include(pb => pb.PurchasePayments);
foreach(var pb in bills){
if(pb.PurchasePayments.Any()){
//do something with the bill and its purchase here
}
}
But don't do this if all you're going to do is add a message to an error list; it's a lot of data to download for the sake of looking through and finding one bill record that might have a payment record - that is better done by the first recommendation that asks the DB for a simple boolean - "is there any payment anywhere for this purchaseId?"
Have you tried this:
var hasPayment = _context.PurchasePayment.Where(x => _context.PurchaseBill.Where(a => a.PurchaseId == obj.Id).Any(y => y.PurchaseBillId == x.PurchaseBillId)).Any();
I tried an example here:
https://dotnetfiddle.net/uTs6pd
You can implement something like this:
var PurchaseId=1;
var result = _context.PurchasePayment.Where(x=>_context.PurchaseBill.Where(y=>y.PurchaseId==PurchaseId).Select(y=>y.PurchaseBillId).ToList().Contains(x.PurchaseBillId)).Count();
Related
I have a few tables and this is what I need to achieve.
This gets all the rows from one table
var FRA = from prod in _cctDBContext.Fra
where prod.ActTypeId == 1
From within that, I get all the rows where ActTypeID.
Then I need to query another table from with the ID's get from that
foreach (var item in FRA)
{
var FRSA = _cctDBContext.Frsa
.Select(p => new { p.Fraid, p.Frsa1,
p.Frsaid, p.CoreId,
p.RelToEstId, p.ScopingSrc,
p.Mandatory })
.Where(p => p.Fraid == item.Fraid)
.ToList();
}
I then need to push each one of these to Entity Framework. I usually do it this way:
foreach (var item in FRA)
{
var FinanicalReportingActivity = new FinancialReportingActivity { FinancialReportingActivityId = item.Fraid, ScopingSourceType = item.ScopingSrc, Name = item.Fra1, MandatoryIndicator = item.Mandatory, WorkEffortTypeId = 0 };
_clDBContext.FinancialReportingActivity.AddRange(FinanicalReportingActivity);
}
But because I have used 2 for each loops, I cannot get the variables to work because I cannot find a way to get local variables as the entity context.
Can anyone think of a better way to code this?
Thanks
It looks like you can do this as a single join:
var query =
from prod in _cctDBContext.Fra
where prod.ActTypeId == 1
join p in _cctDBContext.Frsa on prod.Fraid equals p.Fraid
select new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
};
It looks like you are loading data from one set of entities from one database and want to create matching similar entities in another database.
Navigation properties would help considerably here. Frsa appear to be a child collection under a Fra, so this could be (if not already) wired up as a collection within the Fra entity:
Then you only need to conduct a single query and have access to each Fra and it's associated Frsa details. In your case you look to be more interested in the associated FRSA details to populate this ReportingActivity:
var details = _cctDBContext.Fra
.Where(x => x.ActTypeId == 1)
.SelectMany(x => x.Frsa.Select(p => new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
}).ToList();
though if the relationship is bi-directional where a Fra contains Frsas, and a Frsa contains a reference back to the Fra, then this could be simplified to:
var details = _cctDBContext.Frsa
.Where(x => x.Fra.ActTypeId == 1)
.Select(p => new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
}).ToList();
Either of those should give you the details from the FRSA to populate your reporting entity.
I have a table where all vehicles are registered and another table where I have millions of pings for each registered vehicle.
I'm trying to select the last ping from each vehicle that has sent a ping in the last 30 minutes using the LINQ QUERY. I've done the code below through the "for each" idea, but I'm not sure if it is the best way to do.
I would like to know if there is any better way to select this using a single line? I know that I can "group by" them by vehicle_fleetNumber but I couldn't achieve the proper result as the TAKE() is limiting the final result.
var timeRestriction = DateTime.UtcNow.AddMinutes(-30);
var x = _db.Vehicles.Where(r=> r.isActive.Equals(true) && r.helperLastPing > timeRestriction);
foreach (var vehicle in x)
{
var firstOrDefault = _db.Tracks.OrderByDescending(r => r.collectedOn)
.FirstOrDefault(r => r.vehicle_fleetNumber.Equals(vehicle.fleetNumber));
}
return View();
Thank you,
Yes, you should do it in the database by joining both tables and using GroupBy:
var query = from v in _db.Vehicles
join t in _db.Tracks
on v.fleetNumber equals t.vehicle_fleetNumber
where v.isActive && v.helperLastPing > timeRestriction
group t by t.vehicle_fleetNumber into vehicleGroup
select vehicleGroup.OrderByDescending(x => x.collectedOn).First();
foreach(var track in query)
{
// ...
}
Instead of the foreach you can also use query.ToArray or ToList, i don't know what you want to do with it.
If you get moreLinq from nuget you will find the .maxby() method:
for example in a different context:
//get the correct exchange rate
var rateList = _db.lists_ExchangeRates.Where(
rates => rates.Currency == currencyCode);
Decimal? exRate = rateList.MaxBy(rates => rates.LastUpdated).ExchangeRate;
Also see below this gives additional info.
MoreLinq maxBy vs LINQ max + where
In my case if I want the last data that has been save I use this method
var id = db.DPSlips.Max(item => item.Id);
So I thought this might work as will just try
var timeRestriction = DateTime.UtcNow.AddMinutes(-30);
var x = _db.Vehicles.Max(a => a.isActive == true && a.helperLastPing > timeRestriction);
I have a database that contains 3 tables:
Phones
PhoneListings
PhoneConditions
PhoneListings has a FK from the Phones table(PhoneID), and a FK from the Phone Conditions table(conditionID)
I am working on a function that adds a Phone Listing to the user's cart, and returns all of the necessary information for the user. The phone make and model are contained in the PHONES table, and the details about the Condition are contained in the PhoneConditions table.
Currently I am using 3 queries to obtain all the neccesary information. Is there a way to combine all of this into one query?
public ActionResult phoneAdd(int listingID, int qty)
{
ShoppingBasket myBasket = new ShoppingBasket();
string BasketID = myBasket.GetBasketID(this.HttpContext);
var PhoneListingQuery = (from x in myDB.phoneListings
where x.phonelistingID == listingID
select x).Single();
var PhoneCondition = myDB.phoneConditions
.Where(x => x.conditionID == PhoneListingQuery.phonelistingID).Single();
var PhoneDataQuery = (from ph in myDB.Phones
where ph.PhoneID == PhoneListingQuery.phonePageID
select ph).SingleOrDefault();
}
You could project the result into an anonymous class, or a Tuple, or even a custom shaped entity in a single line, however the overall database performance might not be any better:
var phoneObjects = myDB.phoneListings
.Where(pl => pl.phonelistingID == listingID)
.Select(pl => new
{
PhoneListingQuery = pl,
PhoneCondition = myDB.phoneConditions
.Single(pc => pc.conditionID == pl.phonelistingID),
PhoneDataQuery = myDB.Phones
.SingleOrDefault(ph => ph.PhoneID == pl.phonePageID)
})
.Single();
// Access phoneObjects.PhoneListingQuery / PhoneCondition / PhoneDataQuery as needed
There are also slightly more compact overloads of the LINQ Single and SingleOrDefault extensions which take a predicate as a parameter, which will help reduce the code slightly.
Edit
As an alternative to multiple retrievals from the ORM DbContext, or doing explicit manual Joins, if you set up navigation relationships between entities in your model via the navigable join keys (usually the Foreign Keys in the underlying tables), you can specify the depth of fetch with an eager load, using Include:
var phoneListingWithAssociations = myDB.phoneListings
.Include(pl => pl.PhoneConditions)
.Include(pl => pl.Phones)
.Single(pl => pl.phonelistingID == listingID);
Which will return the entity graph in phoneListingWithAssociations
(Assuming foreign keys PhoneListing.phonePageID => Phones.phoneId and
PhoneCondition.conditionID => PhoneListing.phonelistingID)
You should be able to pull it all in one query with join, I think.
But as pointed out you might not achieve alot of speed from this, as you are just picking the first match and then moving on, not really doing any inner comparisons.
If you know there exist atleast one data point in each table then you might aswell pull all at the same time. if not then waiting with the "sub queries" is nice as done by StuartLC.
var Phone = (from a in myDB.phoneListings
join b in myDB.phoneConditions on a.phonelistingID equals b.conditionID
join c in ph in myDB.Phones on a.phonePageID equals c.PhoneID
where
a.phonelistingID == listingID
select new {
Listing = a,
Condition = b,
Data = c
}).FirstOrDefault();
FirstOrDefault because single throws error if there exists more than one element.
There are three tables in the database that are relevant. Advocate, Vendor, and Advocate_Vendor.
The Advocate_Vendor table being the many to many link, has a vendorId and an advocateId.
My end goal is to get back a List<Advocate> object...a collection of advocates that belong to one Vendor. I wrote this:
var list = new List<Advocate>();
foreach (var vendorAdvocates in db.Advocate_Vendors)
{
if (vendorAdvocates.VendorId == vendorId)
{
list.Add(db.Advocates.SingleOrDefault(a => a.AdvocateId == vendorAdvocates.AdvocateId));
}
}
And then this:
var list = (from vendorAdvocates in db.Advocate_Vendors
where vendorAdvocates.VendorId == vendorId
select db.Advocates.SingleOrDefault(a =>
a.AdvocateId == vendorAdvocates.AdvocateId)).ToList();
Is this the best way? Seems wrong, like maybe there could be a more streamlined way to do this using a 'contains' keyword or something that looks a bit more readable...get all the vendor's advocates
thanks
Using a join between Advocate_Vendors and Advocates would be the right way of doing it.
var list = (from vendorAdvocates in db.Advocate_Vendors
join advocates in db.Advocates
on vendorAdvocates.AdvocateId equals advocates.AdvocateId
where vendorAdvocates.VendorId == vendorId
select advocates).ToList();
var list = (from vendorAdvocates in db.Advocate_Vendors
from advocate in db.Advocates
where vendorAdvocates.VendorId == vendorId &&
vendorAdvocates.AdvocateId = advocate.Id
select advocate)
.ToList();
If you set up your foreign keys and navigation properties properly, it should be possible to write this way, or something like it:
var list = (from vendorAdvocates in db.Advocate_Vendors
where vendorAdvocates.VendorId == vendorId
select db.Advocate).ToList();
Say we've got a project that allows user to download things. On the main page, I want to show the Most downloaded files ordered by the number of download! All that using EF.
How can i do this !! I've tried many things with Group By (Its a nightmare when you've got a lot of informations in an object). And i still dunno how to do this...
var query = from details in m_context.TransactionDetails
where details.Chanson != null
group details by details.Items into AnItem
orderby AnItem.Count()
select new Item() {
IdItem = Chansons.Key.IdItem,
ItemState= Chansons.Key.ItemState,
[...This object got something like 20 including links to other objects ... ]
};
Anyone have an idea?
Thanks :o)
Oh and sorry for my english, I'm giving my best but im from Quebec (Usualy talk french).
Salut!
I'm going to guess at your data model a little, here, but I don't think you need to group:
var query = from details in m_context.TransactionDetails
where details.Chanson != null
orderby details.Items.Count() descending
select new Item
{
IdItem = details.Chanson.IdItem,
ItemState= details.Chanson.ItemState,
// ...
};
Bonne chance!
Update: For albums:
var query = from details in m_context.TransactionDetails
where details.DisqueCompact != null
orderby details.Items.Count() descending
select new Item
{
IdItem = details.DisqueCompact.IdItem,
ItemState= details.DisqueCompact.QuelqueChose...
// ...
};
You probably need two queries given your data model.
For grouping data, you can read this How-To from MSDN.
This is an example of how you should do it:
//this is a entity framework objects
CTSPEntities CEntity = new CTSPEntities();
//and this is your example query
var query = (from details in CEntity.Purchase_Product_Details
group details by new { details.Product_Details.Product_Code, details.Product_Details.Product_Name} into Prod
select new
{
PID = Prod.Key.Product_Code,
PName = Prod.Key.Product_Name,
Amount = Prod.Sum(c => c.Lot_Amount),
count= Prod.Count()
}).OrderBy(x => x.Amount);
foreach (var item in query)
{
Console.WriteLine("{0},{1},{2},{3}",item.PID,item.PName,item.Amount,item.count);
}
Console.ReadLine();