LINQ query to get count of joined record - c#

Can somebody help me out writing a LINQ query to get record that are joined? I have two models below. I want to get requirements count that belong to given project and has one or more ProjectTest joined to it.
public class ProjectTest
{
public int ProjectTestID { get; set; }
public int ProjectID { get; set; }
public String Objective { get; set; }
public String Category { get; set; }
public String SubCategory { get; set; }
public String Tags { get; set; }
public virtual ICollection<ProjectRequirement> ProjectRequirements { get; set; }
public virtual ICollection<ProjectTestStep> ProjectTestSteps { get; set; }
}
public class ProjectRequirement
{
public int ProjectRequirementID { get; set; }
public int ProjectID { get; set; }
[Display(Name = "Req No.")]
public String ProjectRequirementIDStr { get; set; }
[Display(Name = "Module")]
public String ModuleName { get; set; }
[Display(Name = "Description")]
public String Description { get; set; }
public virtual ICollection<ProjectTest> ProjectTests { get; set; }
}
I just tried to write it as follows but does not seem working.
db.ProjectRequirements
.Where(e => e.ProjectID == activeProjectID &&
e.ProjectTests
.Select(ept => ept.ProjectTestID)
.Count() > 0)
.Select(e => e.ProjectRequirementID)
.Count();

Currently you are counting the number of ProjectRequirement objects that have a given id and that have at least 1 ProjectTest.
If you want to count the amount of ProjectTests you have for a given ProjectId:
var number = db.ProjectRequirements.Where(e => e.ProjectID == activeProjectID)
.Sum(e => e.ProjectTests.Count());

Related

How to get data from child to parent entity framework core?

I have two table like this -
public class Job
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime AddedTime { get; set; } = DateTime.Now;
public DateTime LastEdit { get; set; } = DateTime.Now;
public string Explanation { get; set; }
public string PhotoString { get; set; }
public bool isActive { get; set; } = true;
public int CompanyId { get; set; }
public Company Company { get; set; }
}
and company -
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Explanation { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string PhotoString { get; set; }
public bool isActive { get; set; } = true;
public int AppUserId { get; set; }
public AppUser AppUser { get; set; }
public List<Job> Jobs { get; set; }
}
I only want to get AppUserId from Company and all Jobs from every Company. I tried this and it gave me error.
using var context = new SocialWorldDbContext();
return await context.Jobs.Where(I => I.isActive == true && I.Company.isActive).Include(I=>I.Company.AppUserId).ToListAsync();
So my question is there any way I can get this data from parent?
Include adds whole entities to the output. To add just one property use Select, something like
context.Jobs
.Where(I => I.isActive == true && I.Company.isActive)
.Select(e => new {Job=e, CompanyAppUserId = e.Company.AppUserId})
.ToListAsync();

How to modify this LINQ statement to show bundles with count < 3 instead of CountWithinBundle < 3

I am creating bundles in my app and a bundle is defined as follows
Having a BundleId != null
Having a CountWithinBundle
A bundle is "full" when it has 3 members
I am trying to write a query to find "non full" bundles, below is where I am at but it gives me the second within a bundle every time since I am using the < 3
How can I modify this so that it gives me the last"non full" bundle Item, i,e an ItemInBasket where there are less than 3 entries with the same bundleId and Department so I can add a new item into the same bundle
var itemInBasket = basketToUpdate.ItemsInBasket.OrderByDescending(c => c.ThisItemsCountWithinBundle)
.Where(s => !string.IsNullOrEmpty(s.BundleId))
.Where(i => i.ThisItemsCountWithinBundle < 3)
.Where(s => s.Item.Department == itemToAdd.Item.Department)
.FirstOrDefault();
the class model looks like this
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace slapi.Models
{
class BasketModel
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
public string UserId { get; set; }
public string Brand { get; set; }
public int BasketLevel { get; set; }
//Start New Basket props
public int MaxBasketLevel { get; set; } = 6;
public Nullable<decimal> BasketLevelProgress { get; set; }
public decimal BasketLevelDiscount { get; set; }
public decimal WhitePriceStoreSummary { get; set; }
public Nullable<decimal> RedPriceStoreSummary { get; set; }
public Nullable<decimal> CheckoutDiscount { get; set; }
public Nullable<decimal> CheckoutDiscountPercent { get; set; }
public string Currency { get; set; } = "SEK";
public List<XForYStatusInformation> XForYInformations { get; set; }
//End New Basket props
public string ConsumerName { get; set; }
public string StoreId { get; set; }
public bool IsRedeemed { get; set; } = false;
public bool IsDeleted { get; set; } = false;
public List<ItemInBasket> ItemsInBasket { get; set; }
public string CreatedDate { get; set; }
public string CreatedDateUtc { get; set; }
public string CreatedBy { get; set; }
public string UpdatedDate { get; set; }
public string UpdatedDateUtc { get; set; }
public string UpdatedBy { get; set; }
public Nullable<int> CountHistory { get; set; } = 0;
}
class ItemInBasket
{
public StorelensItemModel_V2 Item { get; set; }
public Nullable<int> ItemRowPosition { get; set; }
public bool UsedForWeightCalculation { get; set; }
public bool IsPaused { get; set; }
public string BundleId { get; set; }
public int ThisItemsCountWithinBundle { get; set; } = 0;
public int BundleNeededQty { get; set; } = 3;
}
class XForYStatusInformation
{
public string Sticker { get; set; }
public string Text { get; set; }
public string BundleId { get; set; }
public string Department { get; set; }
}
}
The problem is that you're querying individual items, so you lose their mutual relationships (i.e. belonging to the same basket). The basketToUpdate has all required information, basically something like this:
basketToUpdate
.Select(b => new
{
Bundles = b.ItemsInBasket
.GroupBy(i => i.BundleId)
.Select(g => new
{
BundleId = g.Key,
ItemCount = g.Count(),
LastItem = g.OrderByDescending(c => c.ThisItemsCountWithinBundle)
.FirstOrDefault()
})
})
.Where(x => x.Bundles.Any(b => ItemCount < 3))
This gives you baskets with non-full bundles in which you can filter the bundles with ItemCount < 3.
I don't know the function of this s.Item.Department == itemToAdd.Item.Department predicate, so I didn't try to fit it in.

Include in EF C#

I have three tables:
Member, business and business address
I'm able to fetch the business with member using Include, but I'm trying to get businessAddress, it is asking for direct relationship i guess.
Here is my models:
[Table("member")]
public partial class Member
{
public Member()
{
Business = new HashSet<Business>();
// BusinessAddress = new HashSet<BusinessAddress>();
}
[Key]
public int memberId { get; set; }
public int chapterid { get; set; }
public string title { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public bool IsActive { get; set; }
public string classification { get; set; }
public int SortOrder { get; set; }
public virtual ICollection<Business> Business { get; set; }
// public virtual ICollection<BusinessAddress> BusinessAddress { get; set; }
}
Business
[Table("Business")]
public partial class Business
{
public Business()
{
BusinessAddress = new HashSet<BusinessAddress>();
}
[Key]
public int BusinessID { get; set; }
public int? categoryid { get; set; }
public int? subcategoryid { get; set; }
public int memberid { get; set; }
public string businessname { get; set; }
public string dealingin { get; set; }
public int? sortOrder { get; set; }
[ForeignKey("memberid")]
public Member Member { get; set; }
public ICollection<BusinessAddress> BusinessAddress { get; set; }
}
BusinessAddress
[Table("BusinessAddress")]
public partial class BusinessAddress
{
[Key]
public int businessaddressid { get; set; }
public int businessid { get; set; }
[ForeignKey("businessid")]
public virtual Business Business { get; set; }
public string address { get; set; }
}
Below is my EF query:
var list = _dbContext.Member.Include("Business").OrderByDescending(x => x.SortOrder).ThenBy(x => x.firstname).ToList();
I want to get Member with business and BusinessAddresses. I have tried Include("BusinesADdress") that didn't work, Help me please.
Try using Include accepting lambda selector followed by ThenInclude:
var list = _dbContext.Member
.Include(m => m.Business)
.ThenInclude(b => b.BusinessAddress)
.OrderByDescending(x => x.SortOrder)
.ThenBy(x => x.firstname)
.ToList();
Also you can just append all needed relations via . in the Include call but in general I would recommend against it cause the first approach is type safe:
var list = _dbContext.Member
.Include("Business.BusinessAddress")
.OrderByDescending(x => x.SortOrder)
.ThenBy(x => x.firstname)
.ToList();

Updating entity tree with deep nested entities

My app deals with saving orders received from an external system. The order contains child items like line items, address, fulfillments, refunds > refund items etc.
Currently, I use an ugly looking code to detect what has changed in each entity by its External Id. Can someone recommend me a better way? :)
Following is a simplified entity model of Order
public class Order
{
public long Id { get; set; }
public string ExternalOrderId { get; set; }
public List<LineItem> LineItems { get; set; }
public List<Fulfillment> Fulfillments { get; set; }
public ShippingAddress ShippingAddress { get; set; }
public List<Refund> Refunds { get; set; }
public string FinancialStatus { get; set; }
public string FulfillmentStatus { get; set; }
}
public class LineItem
{
public long Id { get; set; }
public string ExternalLineItemId { get; set; }
public string SKU { get; set; }
public int Quantity { get; set; }
public long OrderId { get; set; }
}
public class Fulfillment
{
public long Id { get; set; }
public string ExternalFulfillmentId { get; set; }
public string Status { get; set; }
public string TrackingUrl { get; set; }
public long OrderId { get; set; }
}
public class ShippingAddress
{
public long Id { get; set; }
public string ExternalShippingAddressrId { get; set; }
public string Addres { get; set; }
public long OrderId { get; set; }
}
public class Refund
{
public long Id { get; set; }
public string ExternalRefundId { get; set; }
public List<RefundedItem> LineItems { get; set; }
public string CancelledReason { get; set; }
public long OrderId { get; set; }
}
public class RefundedItem
{
public long Id { get; set; }
public string ExternalRefundedItemId { get; set; }
public string SKU { get; set; }
public int Quantity { get; set; }
}
My sample code:
private async Task ManageFulfillments(long orderId, Order order)
{
if (order.Fulfillments == null || !order.Fulfillments.Any()) return;
var newFulfillmentIds = order.Fulfillments.Select(c => c.ExternalFulfillmentId).ToList();
var dbFulfillments = await _fulfillmentRepository.GetAll().IgnoreQueryFilters()
.Where(c => c.OrderId == orderId)
.Select(c => new { c.Id, c.ExternalFulfillmentId }).ToListAsync();
var dbFulfillmentIds = dbFulfillments.Select(c => c.ExternalFulfillmentId).ToList();
// Delete Fulfillments that are not present in new Fulfillments list
var deletedFulfillments = dbFulfillmentIds.Except(newFulfillmentIds).ToList();
if (deletedFulfillments.Any())
{
await _fulfillmentRepository.DeleteAsync(c =>
deletedFulfillments.Contains(c.ExternalFulfillmentId) && c.ExternalOrderId == orderId);
}
// Update existing Fulfillments ids
order.Fulfillments
.Where(c => dbFulfillmentIds.Contains(c.ExternalFulfillmentId))
.ToList()
.ForEach(async c =>
{
c.Id = dbFulfillments.Where(p => p.ExternalFulfillmentId == c.ExternalFulfillmentId)
.Select(p => p.Id).FirstOrDefault();
await _fulfillmentRepository.UpdateAsync(c);
});
// New Fulfillments will automatically be added by EF
}
I have similar code in place to update other entites as well and I'm not proud of it!

Calculate Account Receivables using LINQ

How to calculate account receivable using LINQ.
I have tried this but stuck here.
I have done this in SQL but I want this in LINQ so I can use it in my MVC project.
var sale = saleslist.GroupBy(s => s.BuyerId).Select(s => s.Sum(u => u.Amount)).ToList();
var receipt = receiptslist.GroupBy(r => r.StakeHolderId).Select(t => t.Sum(u => u.Amount)).ToList();
List<AccountReceivablesVM> res = db.StakeHolders
.Where(r=>r.StakeHolderTypeId == "0b85a69e-55f2-4142-a49d-98e22aa7ca10")
.Select(rvm => new AccountReceivablesVM
{
CompanyName = rvm.CompanyName,
Receivables = //don't know what to do here
}).ToList();
Models:
public class StakeHolder
{
public string StakeHolderId { get; set; }
public string CompanyName { get; set; }
public string Address { get; set; }
public string Contact { get; set; }
public string StakeHolderTypeId { get; set; }
}
public class Sale
{
public string SaleId { get; set; }
public string RefNo { get; set; }
public DateTime Date { get; set; }
public string BuyerId { get; set; }
public string Description { get; set; }
public Nullable<double> Amount { get; set; }
}
public class PaymentsAndReceipt
{
public string PaymentAndReceiptId { get; set; }
public Nullable<int> VoucherNo { get; set; }
public DateTime Date { get; set; }
public string StakeHolderId { get; set; }
public string Description { get; set; }
public Nullable<double> Amount { get; set; }
}
public class AccountReceivablesVM
{
public string CompanyName { get; set; }
public Nullable<double> Receivables { get; set; }
}
Expected Result:
You can join first with stakeholderId and then sum the amount and then group by with company name and stakeholder id, however I write the code in Linq. I have considered the stakeholderid as the primary key of your table just because you have not mentioned the schema of stakeholder so.
var result = from s in db.StakeHolders
join pr in db.PaymentsAndReceipt on s.StakeHolderId equals pr.StakeHolderId
where StakeHolderTypeId == "0b85a69e-55f2-4142-a49d-98e22aa7ca10"
group s by new { s.StakeHolderId,s.CompanyName} into p
select new
{
StakeHolderId= p.Key.StakeHolderId,
CompanyName= p.Key.CompanyName,
Receivables = string.Format("{0:C}", p.Sum(y => y.Amount))
};

Categories

Resources