C# web api data filtration - c#

Good day,
I am doing Web api rest project and want to include product search for products by size and color, but I want to be able search for example:
1 One size
[httpGet][Route("oneSize/{sizeID}")]
2 Two Sizes
[httpGet][Route("TwoSizes/{sizeID1}/{sizeID2}")]
3 One size/ One color
[httpGet][Route("OneSizeOneColor/{sizeID1}/{ColorID}")]
4 Two sizes/ One color
[httpGet][Route("TwoSizeOneColor/{sizeID1}/{sizeID2}/{ColorID}")]
etc.
Do I need to create end point for every tipe of search or is there a smarter way of doing it?

You should use the query params. You can add them via FromQuery attribute:
[HttpGet]
public IActionResult SearchProducts([FromQuery] int[] sizeIds, [FromQuery] int[] colorIds) {
}
You can replace int with string if you have string Ids.
For example, if you want to make a request with sizes 1 and 2, and color 3 and 4, the request would look like this: https://localhost:5001/your-endpoint-name?sizeIds=1&sizeIds=2&colorIds=3&colorIds=4
So query is a list of key=value url parameters after the ? separated by & sign
EDIT
You can easily query the database with the sql IN operator.
In EF Core, it would look something like this:
IQuaryable<Product> query = dbContext.Products;
if (sizeIds.Length > 0) {
query= query.Where(p => sizeIds.Contains(p.SizeId));
}
if (colorIds.Length > 0) {
query= query.Where(p => colorIds.Contains(p.ColorId));
}
List<Product> result = await query.ToListAsync();
It would be translated to the following SQL:
SELECT * FROM Products
WHERE Products.SizeId IN (1, 2) AND Products.ColorId IN (3, 4);

The problem is that I have nested classess
public class ProductBase
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<ProductVariant> Variants { get; set; } = new List<ProductVariant>();
public int BaseImageId { get; set; } = 0;
public string BaseImagePath { get; set; } = string.Empty;
}
public class ProductVariant
{
public int Id { get; set; }
public int Quantity { get; set; }
public int ProductBaseId { get; set; }
public int ProductSizeId { get; set; }
public ProductSize ProductSize { get; set; }
public int ProductColorId { get; set; }
public ProductColor ProductColor { get; set; }
public IEnumerable<ImageVariant> imageVariants { get; set; } = new List<ImageVariant>();
}
public class ProductSize
{
public int Id { get; set; }
public string Size { get; set; }
}
public class ProductColor
{
public int Id { get; set; }
public string Color { get; set; }
}
I am trying something like this
public async Task<IQueryable<Models.ProductBase>> SearchProducts(int[] SizeIds, int[] ColorIds )
{
IQueryable<Models.ProductBase> query = _dataContext.ProductBases
.Include(pb => pb.Variants).ThenInclude(v => v.ProductSize)
.Include(pb => pb.Variants).ThenInclude(v => v.ProductColor)
.Include(pb => pb.Variants).ThenInclude(v => v.imageVariants);
if(SizeIds.Length > 0)
{
query = query.Where(pb => SizeIds.Contains(pb.Variants.Any(pb.Variants.doesnotWork));
}
if(ColorIds.Length > 0)
{
query = query.Where(pb => ColorIds.Contains(pb.Variants.Contains(pb.Variants.doesNotWork)));
}
List<ProductBase> result = await query.ToListAsync();
}

Fixed , this is working now
public async Task<IEnumerable<Models.ProductBase>> SearchProducts(int[] SizeIds, int[] ColorIds )
{
IQueryable<Models.ProductBase> query = _dataContext.ProductBases
.Include(pb => pb.Variants).ThenInclude(v => v.ProductSize)
.Include(pb => pb.Variants).ThenInclude(v => v.ProductColor)
.Include(pb => pb.Variants).ThenInclude(v => v.imageVariants);
if(SizeIds.Length > 0)
{
query = query.Where(pb => pb.Variants.ToList().Any(v => SizeIds.Contains(v.ProductSizeId)));
}
if(ColorIds.Length > 0)
{
query = query.Where(pb => pb.Variants.ToList().Any(v => ColorIds.Contains(v.ProductColorId)));
}
List<Models.ProductBase> result = await query.ToListAsync();
return result;
}

Related

Filter data from 2 lists with diferent models C#

I have this models
public class RoutingAttributeModel
{
public int Bus_No { get; set; }
public int Attribute_No { get; set; }
public string Attribute_Name { get; set; }
public string Status { get; set; }
public string Notes { get; set; }
}
public class AgentRoutingAttributeModel
{
public int Agent_No { get; set; }
public int Bus_No { get; set; }
public int Attribute_No { get; set; }
public string Attribute_Name { get; set; }
public string Status { get; set; }
}
List<RoutingAttributeModel> lstComplete = new List<RoutingAttributeModel>();
List<AgentRoutingAttributeModel> lstAssigned = new List<AgentRoutingAttributeModel>();
Filled this with some data
Is it possible to filter with Linq? I want to save in a new list the diferent content between lstComplete and lstAssigned
I was trying to join both lists but got stuck there
var results1 = from cl in lstComplete
join al in lstAssigned
on cl.Attribute_No equals al.Attribute_No
select cl;
you can use linq
as my understanding, you try to find linked by attribute_No records and have a list of not matching properties?
lstComplete.Add(new RoutingAttributeModel(){
Attribute_Name = "aaa",
Attribute_No = 1,
Bus_No = 1,
Notes = "",
Status = "status"
});
lstAssigned.Add(new AgentRoutingAttributeModel()
{
Attribute_No = 1,
Agent_No = 10,
Bus_No = 1,
Attribute_Name = "bbb",
Status = "status2"
});
var lst = lstComplete
.Join(lstAssigned,
complete => complete.Attribute_No,
assigned => assigned.Attribute_No,
(complete, assigned) => new { lstComplete = complete, lstAssigned = assigned })
.Select(s => new { s.lstComplete, s.lstAssigned})
.Where(w=>
w.lstAssigned.Attribute_Name != w.lstComplete.Attribute_Name
|| w.lstAssigned.Bus_No != w.lstComplete.Bus_No
)
.ToList()
.Dump();
so result would be
You could try the following query
var filteredList = lstComplete
.Where(x => !lstAssigned.Any(y => y.Attribute_No == x.Attribute_No));

Add values to a list inside a list Linq

I am having a class like this.
public class CameraModel
{
public int JobId { get; set; }
public int ViewId { get; set; }
public Guid ViewGuid { get; set; }
public string Name { get; set; }
public int ViewNum { get; set; }
public int LayoutID { get; set; }
public List<CameraViewItemModel> CameraViewItems { get; set; }
}
The CameraViewItemModel class is like this:
public class CameraViewItemModel
{
public int JobID { get; set; }
public Guid ViewGuid { get; set; }
public int ViewID { get; set; }
public int CamNum { get; set; }
public Guid ChannelGuid { get; set; }
public string Name { get; set; }
public ActionType Action { get; set; }
}
Now, I am assigning the list of CameraViewItemModel like this:
// get all the cameramodel's
cameraModels = _unitOfWork.Context.CameraViews.Where(m => m.JobId == siteId)
.Select(m => new CameraModel
{
JobId = m.JobId,
ViewId = m.ViewId,
ViewGuid = m.ViewGuid,
Name = m.Name,
ViewNum = m.ViewNum,
LayoutID = m.LayoutId
}).ToList();
// get all the cameraviewitemmodels
cameraViewItemModels =
(from cameraView in _unitOfWork.Repository<CameraViews>().Get(x => x.JobId == siteId).Result
join cameraViewItem in _unitOfWork.Repository<CameraViewItems>().Get(x => x.JobId == siteId)
.Result on cameraView.ViewId equals cameraViewItem.ViewId into CameraViewItemResults
from cameraViewItemResult in CameraViewItemResults.DefaultIfEmpty()
join cameraChannel in _unitOfWork.Repository<CameraChannels>().Get(x => x.JobId == siteId)
.Result on (cameraViewItemResult == null ? new Guid() : cameraViewItemResult.ChannelGuid) equals cameraChannel.ChannelGuid into CameraChannelResults
from cameraChannelResult in CameraChannelResults.DefaultIfEmpty()
select new CameraViewItemModel
{
JobID = cameraView.JobId,
ViewID = cameraView.ViewId,
ViewGuid = cameraView.ViewGuid,
CamNum = cameraViewItemResult.CamNum,
ChannelGuid = cameraChannelResult.ChannelGuid,
Name = cameraChannelResult.Name
}).ToList();
// then do a 'join' on JobId, ViewId and ViewGuid and assign the list of cameraviewitemmodels to cameraModels.
foreach (var cameraModel in cameraModels)
{
cameraModel.CameraViewItems = (from cameraViewItem in cameraViewItemModels
where cameraModel.JobId == cameraViewItem.JobID
&& cameraModel.ViewId == cameraViewItem.ViewID
&& cameraModel.ViewGuid == cameraViewItem.ViewGuid
select cameraViewItem).ToList();
}
return cameraModels;
There are three tables in database:
CameraViews, CameraViewItems, CameraChannels.
CameraViews is the main table. It is left joined with CameraViewItems and CameraChannels to get the desired result. There may not be any data in CameraViewItems and CameraChannels for a corresponding CameraView.
Is it possible to assign the list of CameraViewItemModels to CameraModels in a single linq statement.
Here is a simple way to add values to a sub list, dunno if this is what you mean. You can keep selecting sub lists if that is necessary.
var parent_lst = new List<List<string>>(); // Root/parent list that contains the other lists
var sub_lst = new List<string>(); // Sub list with values
var selected_parent_lst = parent_lst[0]; // Here I select sub list, in this case by list index
selected_parent_lst.Add("My new value"); // And here I add the new value

Mapping between models efficiently

I'm a bit new to asp.net core. In this query, it keeps on requerying the db on every node to map from OrgStructures to ToOrgStructureModel is there a way we can make this more efficient:
This is the area where it keeps on requerying the db: .Select(org => org.ToOrgStructureModel(db.OrgStructures.Where(s => s.ParentNodeId == org.NodeId).Count() > 0))
Whole query:
public virtual IList<OrgStructureModel> GetAll()
{
using (var db = _context)
{
var result = db.OrgStructures
.Where(e => e.FiscalYear == 19)
.Select(org => org.ToOrgStructureModel(db.OrgStructures.Where(s => s.ParentNodeId == org.NodeId).Count() > 0))
.ToList();
_session.SetObjectAsJson("OrgStructure", result);
return result;
}
}
ToOrgStructureModel:
public static OrgStructureModel ToOrgStructureModel(this OrgStructure org, bool hasChildren)
{
return new OrgStructureModel
{
NodeId = org.NodeId,
ParentNodeId = org.ParentNodeId,
Name = org.Name,
DepartmentCode = org.DepartmentCode,
Acronym = org.Acronym,
LegacyId = org.LegacyId,
hasChildren = hasChildren
};
}
OrgStructureModel:
public class OrgStructureModel
{
[ScaffoldColumn(false)]
public int? NodeId { get; set; }
[Required]
public string Name { get; set; }
public string Acronym { get; set; }
public string DepartmentCode { get; set; }
public int? ParentNodeId { get; set; }
public int? LegacyId { get; set; }
public int FiscalYear { get; set; }
public int DepartmentId { get; set; }
[ScaffoldColumn(false)]
public bool hasChildren { get; set; }
public OrgStructure ToEntity()
{
return new OrgStructure
{
NodeId = NodeId,
Name = Name,
Acronym = Acronym,
ParentNodeId = ParentNodeId,
DepartmentCode = DepartmentCode,
LegacyId = LegacyId,
FiscalYear = FiscalYear,
DepartmentId = DepartmentId
};
}
}
Avoid using custom methods when using Linq-to-sql.
Here's a working alternative that doesn't use ToOrgStructureModel method:
var result = db.OrgStructures
.Where(e => e.FiscalYear == 19)
.Select(org => new OrgStructureModel
{
NodeId = org.NodeId,
ParentNodeId = org.ParentNodeId,
Name = org.Name,
DepartmentCode = org.DepartmentCode,
Acronym = org.Acronym,
LegacyId = org.LegacyId,
// Notice using "Any" method instead of comparing count with 0
hasChildren = db.OrgStructures.Any(s => s.ParentNodeId == org.NodeId),
})
.ToList();
You are creating a lot of queries, essentially for every record that it will pull out it will query one more time for each of them to check for hasChildren.
Include the link to the child in your main model (if it's a collection make it a collection),
public class OrgStructureModel
{
...
public int? ChildId {get;set;}
public OrgStructureModel Child {get;set;}
}
And then you can create a check in the query
var result = db.OrgStructures
.Where(e => e.FiscalYear == 19 && e.ChildId != null)
.Select(org => org.ToOrgStructureModel())
.ToList();
Also read this blog post on projection.

Find Unique count on field using LINQ

I am trying to determine the Distinct count for a particular field in a collection of objects.
private static RemittanceCenterBatchSummaryListModel SummarizeFields(RemittanceCenterSummaryListModel remittanceCenterSummaryListModel)
{
var result = remittanceCenterSummaryListModel.RemittanceBatchSummaryRecord.GroupBy(x => new{x.FileId, x.SourceFileName, x.BatchCode, x.BatchType})
.Select(x => new RemittanceCenterBatchSummarizedModel()
{
FileId = x.Key.FileId,
SourceFileName = x.Key.SourceFileName,
BatchCode = x.Key.BatchCode,
BatchType = x.Key.BatchType,
DetailRecordCountAdc = x.Count(y => y.BillingSystemCode == BillingSystemCode.Adc),
DetailRecordCountNotAdc = x.Count(y => y.BillingSystemCode == BillingSystemCode.Exd),
AmountAdc = x.Where(y => y.BillingSystemCode == BillingSystemCode.Adc).Sum(y => y.PaymentAmount),
AmountNotAdc = x.Where(y => y.BillingSystemCode == BillingSystemCode.Exd).Sum(y => y.PaymentAmount),
UniqueFileCount = x.Select(y => x.Key.FileId).Distinct().Count()
});
return CreateSummaryListModel(result);
}
Input entities:
public class RemittanceCenterSummaryListModel
{
public RemittanceCenterSummaryListModel()
{
this.RemittanceBatchSummaryRecord = new List<RemittanceBatchProcessingModel>();
}
public List<RemittanceBatchProcessingModel> RemittanceBatchSummaryRecord { get; private set; }
}
public class RemittanceCenterBatchSummarizedModel
{
public string FileId { get; set; }
public string SourceFileName { get; set; }
public string BatchCode { get; set; }
public string BatchType { get; set; }
public int DetailRecordCountAdc { get; set; }
public int DetailRecordCountNotAdc { get; set; }
public int DetailRecordCountTotal { get; set; }
public decimal AmountAdc { get; set; }
public decimal AmountNotAdc { get; set; }
public decimal AmountTotal { get; set; }
public BillingSystemCode BillingSystemCode { get; set; }
public int UniqueFileCount { get; set; }
}
private static RemittanceCenterBatchSummaryListModel CreateSummaryListModel(IEnumerable<RemittanceCenterBatchSummarizedModel> summaryModels)
{
var summaryModelList = new RemittanceCenterBatchSummaryListModel();
foreach (var summaryRec in summaryModels)
{
var summaryModel = new RemittanceCenterBatchSummarizedModel
{
FileId = summaryRec.FileId,
SourceFileName = summaryRec.SourceFileName,
BatchCode = summaryRec.BatchCode,
BatchType = summaryRec.BatchType,
DetailRecordCountAdc = summaryRec.DetailRecordCountAdc,
DetailRecordCountNotAdc = summaryRec.DetailRecordCountNotAdc,
AmountAdc = summaryRec.AmountAdc,
AmountNotAdc = summaryRec.AmountNotAdc,
UniqueFileCount = summaryRec.UniqueFileCount
};
summaryModelList.RemittanceBatchSummary.Add(summaryModel);
}
return summaryModelList;
}
Example input records:
Record1:
FileId: '123'
SourceFileName: 'test.file.txt'
BatchCode: 'aaa'
BatchType: 'scanned'
PaymentAmount: '50.00'
BillingSystemCode: 'Adc'
Record1:
FileId: '1234'
SourceFileName: 'test.file2.txt'
BatchCode: 'aab'
BatchType: 'scanned'
PaymentAmount: '52.00'
BillingSystemCode: 'Adc'
ActualOuput for UniqueFileCount Field:
UniqueFileCount = 1
ExpectedOutput results for UniqueFileCount Field:
UniqueFileCount = 2
What am I doing wrong?
It sounds like you want the distinct count of FileId for the entire collection and not just for each group, which will always be 1 since FileId is one of the fields you group on. If that is the case then you can just calculate that count first
int distinctFileIds = remittanceCenterSummaryListModel.RemittanceBatchSummaryRecor‌​d
.Select(x => x.FileId)
.Distinct()
.Count();
Then use that in your Linq query
UniqueFileCount = distinctFileIds

Get values from one list inside one list using lambda expression

i am new to lambda expression so i try to solve one problem .but i can't. so can anyone suggest solution for this.
i have one class customer. inside i created another 3 class and create observable collection for 3 classes.i create one observable collection for this customer
ObservableCollection<Customer> customer2;
public class Customer
{
public string CusName { get; set; }
public int CusAge { get; set; }
public ObservableCollection<Bankdetails> bankdetails;
public ObservableCollection<order> orderlist;
public ObservableCollection<orderdetails> orderdetailslist;
public class Bankdetails
{
public string Bankaccno { get; set; }
public string bankname { get; set; }
public int bankid { get; set; }
}
public class order
{
public string ordername { get; set; }
public string orderid { get; set; }
}
public class orderdetails
{
public string orderid { get; set; }
public string itemname { get; set; }
public int itemqty { get; set; }
}
}
i write one linq query for getting values from customer2.anyhow its working .like this i tried to write one lambda query but i can't.
here i adding some values to observable collection.
customer2 = new ObservableCollection<Customer>
{
new Customer()
{
CusName="nixon",CusAge=24,
bankdetails=new ObservableCollection<Customer.Bankdetails>
{
new Customer.Bankdetails()
{
bankid=12,bankname="axis",Bankaccno="09876534"
}
},
orderlist=new ObservableCollection<Customer.order>
{
new Customer.order
{
orderid="Od123",ordername="Express"
}
},
orderdetailslist=new ObservableCollection<Customer.orderdetails>
{
new Customer.orderdetails
{
orderid="Od123",itemname="cpu",itemqty=5
}
}
}
};
this is my linq query
var customer1 = from cus in customer2
from bank in cus.bankdetails
from ord in cus.orderlist
from orddet in cus.orderdetailslist
where ord.orderid == orddet.orderid
select new
{
cus.CusAge,cus.CusName,
bank.Bankaccno,bank.bankid,bank.bankname,
ord.ordername,
orddet.itemname,orddet.itemqty
};
then what will be the lambda query.pls anyone suggest .
Matt's solution extended with the where from the question would be:
var xxx = customer2.SelectMany(cus =>
cus.bankdetails.SelectMany(bank =>
cus.orderlist.SelectMany(ord =>
cus.orderdetailslist.Where(orddet => orddet.orderid == ord.orderid)
.Select(orddet => new
{
cus.CusAge,
cus.CusName,
bank.Bankaccno,
bank.bankname,
orddet.itemname,
orddet.itemqty
}
)
)
)
);
var xxx = customer2.SelectMany(cus =>
cus.bankdetails.SelectMany(bank =>
cus.orderlist.SelectMany(ord =>
cus.orderdetailslist.Select(orddet => new
{
cus.CusAge,
cus.CusName,
bank.Bankaccno,
bank.bankname,
orddet.itemname,
orddet.itemqty
}
)
)
)
);

Categories