Way to create composite objects from a single (flat) database query - c#

I am getting product data from our ERP through SQL queries whereby the returned data is very flat- at the Size level. A product has 3 levels:
Style
Colours
Sizes
A style has many colours and a colour has many sizes.
I have created the following models:
public class Ap21Style
{
public int StyleIdx;
public string StyleCode;
public IList<Ap21Clr> Clrs { get; set; } = new List<Ap21Clr>();
}
public class Ap21Clr
{
public int ClrIdx { get; set; }
public string ColourCode { get; set; }
public string ColourName { get; set; }
public string ColourTypeCode { get; set; }
public string ColourTypeName { get; set; }
public IList<Ap21Sku> Skus { get; set; } = new List<Ap21Sku>();
}
public class Ap21Sku
{
public int SkuIdx { get; set; }
public string SizeCode { get; set; }
public int SizeSequence { get; set; }
public string Barcode { get; set; }
}
My ProductResult looks like this:
public int StyleIdx { get; set; }
public int ClrIdx { get; set; }
public int SkuIdx { get; set; }
public string StyleCode { get; set; }
public string ColourCode { get; set; }
public string ColourName { get; set; }
public string SizeCode { get; set; }
public int SizeSequence { get; set; }
public string ColourTypeCode { get; set; }
public string ColourTypeName { get; set; }
public string Barcode { get; set; }
public string WebData { get; set; }
What would be an effective way to loop over the results and create the Ap21Style models whereby they are a composite object with Ap21Clr's, then at the row level, the Colours have Ap21Sku's?

Assuming something like this
List<ProductResult> products = GetPropducts();
Composing the styles would involve grouping the data by the composite keys
List<Ap21Style> results = products
.GroupBy(p => new { p.StyleIdx, p.StyleCode })
.Select(g => new Ap21Style {
StyleIdx = g.Key.StyleIdx,
StyleCode = g.Key.StyleCode,
Clrs = g.GroupBy(s => new {
s.ClrIdx,
s.ColourCode,
s.ColourName,
s.ColourTypeCode,
s.ColourTypeName
}).Select(g1 => new Ap21Clr {
ClrIdx = g1.Key.ClrIdx,
ColourCode = g1.Key.ColourCode,
ColourName = g1.Key.ColourName,
ColourTypeCode = g1.Key.ColourTypeCode,
ColourTypeName = g1.Key.ColourTypeName,
Skus = g1.Select(s => new Ap21Sku {
Barcode = s.Barcode,
SizeCode = s.SizeCode,
SizeSequence = s.SizeSequence,
SkuIdx = s.SkuIdx
}).ToList()
}).ToList()
}).ToList();

Related

Asp.net core mvc ViewModel with 2 Models

I'm building a feature with a jquery datatable, the idea is to have a list of stores in the parent row, and then when expanding the parent to list all the licensed terminals in child rows that are linked to the store parent row by a StoreLicenseId column. The issue I am having is that I have a ViewModel with two models, one for the list of stores and one for the licensed terminals. I'm busy building the method into my controller, my problem is in the second part of the method where I new up "StoreLicenseDetails = sl.Select(tl => new TerminalListViewModel()", all the references to tl.terminalId and tl.Terminalname. I get this error "StoreListViewModel does not contain a definition for TerminalID and no accessible extension method". I can see why this is happening, so my question really is, how do I include this "second" TerminalListViewModel into my method to form part of the query ?
ViewModel
public partial class StoreListViewModel
{
public List<TerminalListViewModel> StoreLicenseDetails { get; set; } = null!;
public int Id { get; set; }
public Guid StoreLicenseId { get; set; }
[DisplayName("Store Name")]
public string StoreName { get; set; } = null!;
[DisplayName("App One Licenses")]
public int QtyAppOneLicenses { get; set; }
[DisplayName("App Two Licenses")]
public int QtyAppTwoLicenses { get; set; }
[DisplayName("Date Licensed")]
public DateTime DateLicensed { get; set; }
[DisplayName("Licensed Days")]
public int LicenseDays { get; set; }
[DisplayName("Is License Active")]
public bool LicenseIsActive { get; set; }
}
public partial class TerminalListViewModel
{
public int Id { get; set; }
public Guid StoreLicenseId { get; set; }
public Guid TerminalId { get; set; }
public string TerminalName { get; set; } = null!;
public string LicenseType { get; set; } = null!;
public int TerminalLicenseDays { get; set; }
public DateTime DateLicensed { get; set; }
public bool LicenseIsActive { get; set; }
public bool IsDecommissioned { get; set; }
public DateTime LastLicenseCheck { get; set; }
}
Controller Method
//sl = StoreList
//tl = TerminalList
public IEnumerable<StoreListViewModel> GetStoreList()
{
return GetStoreList().GroupBy(sl => new { sl.StoreLicenseId, sl.StoreName, sl.QtyAppOneLicenses,
sl.QtyAppTwoLicenses, sl.DateLicensed, sl.LicenseDays,
sl.LicenseIsActive })
.Select(sl => new StoreListViewModel()
{
StoreName = sl.Key.StoreName,
QtyAppOneLicenses = sl.Key.QtyAppOneLicenses,
QtyAppTwoLicenses = sl.Key.QtyAppTwoLicenses,
DateLicensed = sl.Key.DateLicensed,
LicenseDays = sl.Key.LicenseDays,
LicenseIsActive = sl.Key.LicenseIsActive,
StoreLicenseId = sl.FirstOrDefault().StoreLicenseId,
StoreLicenseDetails = sl.Select(tl => new TerminalListViewModel()
{
StoreLicenseId = tl.StoreLicenseId,
TerminalId = tl.TerminalId,
TerminalName = tl.TerminalName,
}).ToList()
}).ToList();
}
Based on the error,I suppose your GetStoreList() method returns List<OrderListViewModel> ,but your OrderListViewModel doesn't contains properties of TerminalListViewModel,So you got the error
GetStoreList() method should return List<SourceModel>( Source is the model which contains all the properties of StoreListViewModel and TerminalListViewModel)
For example,the link your provided:Multiple child rows in datatable, data from sql server in asp.net core
public class OrderList
{
//source of properties of OrderListViewModel(parent rows)
public int OrderId { get; set; }
public string Customer { get; set; }
public string OrderDate { get; set; }
//source of properties of OrderListDetailViewModel(child rows)
public int KimlikId { get; set; }
public string Product { get; set; }
public string Color { get; set; }
public int Qntty { get; set; }
}
public class OrderListViewModel
{
public int OrderId { get; set; }
public string Customer { get; set; }
public string OrderDate { get; set; }
public List<OrderListDetailViewModel> OrderListDetails { get; set; }
}
public class OrderListDetailViewModel
{
public int KimlikId { get; set; }
public string Product { get; set; }
public string Color { get; set; }
public int Qntty { get; set; }
}
Orderlist contains all columns OrderListViewModel and OrderListDetailViewModel needs.
When it comes to your case,you should
create 3 models (source,parentrow,childrows)
model for parentrows contains the properties
StoreLicenseId,StoreName, QtyAppOneLicenses,QtyAppTwoLicenses, DateLicensed, LicenseDays,LicenseIsActive
and model for childrows contains the other properties of source model
If you still have questions,please show the data you pulled form db,and I'll write a demo for you

Check if some items are same in a c# list

I want to check if some items are same in a list based on a item present in the list.
List<ProductDetailDTO> productDTOs;
The ProductDetailDTO is -
public class ProductDetailDTO
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public byte[] Image { get; set; }
public string Description { get; set; }
public string Brand { get; set; }
public string GUID { get; set; }
public string VariantName { get; set; }
public string VariantValue { get; set; }
public decimal Price { get; set; }
}
Now, I want to display all VariantName and VariantValue with the same GUIDs together.
How can I achieve this?
try with this
productDTOs.GroupBy(x => x.GUID,(key,item) => new
{
VariantName= item.Select(y=>y.VariantName),
VariantValue = item.Select(y => y.VariantValue),
}).ToList()

From the tree structure get list

I have a class CategoryModel in c#, which is an element of a tree:
public class CategoryModel
{
public string Id { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public string ParentCategoryId { get; set; }
public ICollection<string> ChildCategoriesIds { get; set; } = new List<string>();
public ICollection<string> ProductsIds { get; set; } = new List<string>();
}
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
}
The ChildCategoriesIds contains Id class CategoryModel.
The ProductsIds contains Id class Product.
How proccesed data in new classes:
public class CategoryNew
{
public string Uid { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public bool? IsDeleted { get; set; }
public IEnumerable<UidName> ChildCategories { get; set; } = new List<UidName>();
public IEnumerable<UidName> Products { get; set; } = new List<UidName>();
}
public class UidName
{
public string Uid { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public bool? IsDeleted { get; set; }
}
You can specify own constructor for CategoryNew, which will take as an argument object of class CategoryModel, in which you will set all properties of CategoryNew based on values of properties of CategoryModel:
public CategoryNew(CategoryModel cm){
// set properties
}
Then your method would be:
public List<CategoryNew> ConverModelToNew(List<CategoryModel> lstCatModel){
List<CategoryNew> lstCatNew = new List<CategoryNew>();
foreach(var item in lstCatModel){
lstCatNew.Add(new CetagoryNew(item));
}
return lstCatNew;
}
Assuming you are trying to convert one set of object to another set of objects.
First of all, I believe categories shouldl inherit UidName so you will memory more efficiently by reducing duplicate objects.
public class CategoryNew: UidName
{
public IEnumerable<CategoryNew> ChildCategories { get; set; } = new List<CategoryNew>();
public IEnumerable<UidName> Products { get; set; } = new List<UidName>();
}
public class UidName
{
public string Uid { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public bool? IsDeleted { get; set; }
}
// first run to create products
var newProducts = products.Select(p => new UidName {
Uid = p.Id,
Name = p.Name,
NameEnd = p.NameEng
}).ToArray();
// second run to create categories with products
var newCategories = categories.Select(c => new CategoryNew {
Uid = c.Id,
Name = c.Name,
NameEng = c.NameEng,
IsDeleted = (bool?)null, //TODO
Products = newProducts.Where(p => c.ProductIds.Contains(p.Uid))
.ToList()
}).ToArray();
// last run find sub categories
foreach(var category in newCategories) {
var oldCategory = categories.First(c => c.Id == category.Uid);
category.ChildCategories = newCategories.Where(c => oldCategory.ChildCategoriesIds.Contains(c.Uid))
.ToArray();
}

Adding multiple different types of records in some collection and sorting them

I want to send a collection of two different Collections as a Json but in a sorted format. I am not able to do it with Linq. Need little help.And also is there any better way. Thank you!
Here is my action.
public ActionResult GetAllJobPosts()
{
var Institutes = new List<Institute>()
{
new Institute(){InstituteId="ins1",InstituteName="name1",Location="Mumbai"},
new Institute(){InstituteId="ins2",InstituteName="name2",Location="Navi Mumbai"},
new Institute(){InstituteId="ins3",InstituteName="name3",Location="Thiruvananthpuram"}
};
var Companys = new List<Company>()
{
new Company(){CompanyId="com1",CompanyName="comName1",Location="Mumbai"},
new Company(){CompanyId="com2",CompanyName="comName2",Location="Navi Mumbai"},
new Company(){CompanyId="com3",CompanyName="comName3",Location="Mumbai"}
};
var Organizations = new List<Organization>()
{
new Organization(){OrganizationId="org1",OrganizationName="orgName1",Location="Navi Mumbai"},
new Organization(){OrganizationId="org2",OrganizationName="orgName2",Location="Navi Mumbai"},
new Organization(){OrganizationId="org3",OrganizationName="orgName3",Location="Mumbai"},
};
var CompanyJobPosts = new List<CompanyJobPost>()
{
new CompanyJobPost(){CompanyId="com1",CompanyJobPostId="com1jp1",CreatedOn=System.DateTime.Now.AddDays(-2),JobDiscription="Tester",KeySkils="Sylanium"},
new CompanyJobPost(){CompanyId="com1",CompanyJobPostId="com1jp2",CreatedOn=System.DateTime.Now.AddDays(-3),JobDiscription="Developer",KeySkils="C#"},
new CompanyJobPost(){CompanyId="com2",CompanyJobPostId="com2jp1",CreatedOn=System.DateTime.Now.AddDays(-5),JobDiscription="Tester",KeySkils="Sylanium"},
new CompanyJobPost(){CompanyId="com2",CompanyJobPostId="com2jp2",CreatedOn=System.DateTime.Now.AddDays(-6),JobDiscription="Developer",KeySkils="C#"},
new CompanyJobPost(){CompanyId="com3",CompanyJobPostId="com3jp1",CreatedOn=System.DateTime.Now.AddDays(-7),JobDiscription="Tester",KeySkils="Sylanium"},
new CompanyJobPost(){CompanyId="com3",CompanyJobPostId="com3jp2",CreatedOn=System.DateTime.Now.AddDays(-8),JobDiscription="Developer",KeySkils="C#"}
};
var InstituteJobPosts = new List<InstituteJobPost>()
{
new InstituteJobPost(){InstituteId="ins1",InstituteJobPostId="ins1jp1",CreatedOn=System.DateTime.Now.AddDays(-1),JobDiscription="Trainer",KeySkils="C#",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins1",InstituteJobPostId="ins1jp2",CreatedOn=System.DateTime.Now.AddDays(-8),JobDiscription="Developer",KeySkils="Java",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins2",InstituteJobPostId="ins2jp1",CreatedOn=System.DateTime.Now.AddDays(-1),JobDiscription="Trainer",KeySkils="Java",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins2",InstituteJobPostId="ins2jp2",CreatedOn=System.DateTime.Now.AddDays(-8),JobDiscription="Developer",KeySkils=".Net",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins3",InstituteJobPostId="ins3jp1",CreatedOn=System.DateTime.Now.AddDays(-1),JobDiscription="Trainer",KeySkils="C#",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins3",InstituteJobPostId="ins3jp2",CreatedOn=System.DateTime.Now.AddDays(-8),JobDiscription="Developer",KeySkils="Java",ExtraField="MDifferent"}
};
var allJobPosts=new List<object>();
foreach (var item in CompanyJobPosts)
{
allJobPosts.Add(new { JType = "Company", JobPost = item });
}
foreach (var item in InstituteJobPosts)
{
allJobPosts.Add(new { JType = "Institute", JobPost = item });
}
//var allJobPostsOrderdByDate=??
return Json(allJobPosts, JsonRequestBehavior.AllowGet);
}
Here are My Models just to make it simple.
namespace WebApplication1.Models
{
public class Company
{
public string CompanyId { get; set; }
public string CompanyName { get; set; }
public string Location { get; set; }
}
public class Organization
{
public string OrganizationId { get; set; }
public string OrganizationName { get; set; }
public string Location { get; set; }
}
public class Institute
{
public string InstituteId { get; set; }
public string InstituteName { get; set; }
public string Location { get; set; }
}
public class CompanyJobPost
{
public string CompanyJobPostId { get; set; }
public string CompanyId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
}
public class OrganizationJobPost
{
public string OrganizationJobPostId { get; set; }
public string OrganizationId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
public string ExtraField2 { get; set; }
}
public class InstituteJobPost
{
public string InstituteJobPostId { get; set; }
public string InstituteId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
public string ExtraField { get; set; }
}
}
And finally my sweet view
<input name="GetAllJobPosts" id="GetAllJobPosts" type="submit" value="Search Jobs">
<ul id="JobPostList"></ul>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script type="text/javascript">
$("#GetAllJobPosts").click(function () {
var actionUrl = '#Url.Action("GetAllJobPosts", "Default")';
$.getJSON(actionUrl, displayDetailData);
});
function displayDetailData(response) {
if (response != null) {
for (var i = 0; i < response.length; i++) {
$("#JobPostList").append("<li>" + response[i].JType + " " + (response[i].JobPost).CreatedOn + "</li>")
}
}
}
Thank You!
Based on your comments, I can only assume the following, so will do my best to point you in the correct direction:
You do not have a common object of inheritance between the two - that is, you wish to sort them on property x, but property x, is not defined to exist in both.
So, solution? Easy: add a common interface, class or abstract class between the two that has the property you wish to sort by, then sort by it:
public interface IJobPost
{
DateTime CreatedOn { get; set; }
}
Then modify your three existing objects:
public class CompanyJobPost : IJobPost
{
public string CompanyJobPostId { get; set; }
public string CompanyId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
}
public class OrganizationJobPost : IJobPost
{
public string OrganizationJobPostId { get; set; }
public string OrganizationId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
public string ExtraField2 { get; set; }
}
public class InstituteJobPost : IJobPost
{
public string InstituteJobPostId { get; set; }
public string InstituteId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
public string ExtraField { get; set; }
}
Lastly, the action:
var allJobPosts=new List<IJobPost>();
// Add other posts to allJobPosts here.
var allJobPostsOrderdByDate = allJobPosts.OrderBy(x => x.CreatedOn).ToList();
Note: Code is untested. LINQ query may or may not work. Did this all from memory.
Edit: You can also share any other properties you wish to force between the three of them. That is what an interface or abstract class is for. That also means you can share Description or other properties.

Accessing properties from multiple classes

I am creating a web application and I have two classes:
public class MOrderMain
{
public int ID { get; set; }
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public DateTime OrderDate { get; set; }
public string BillingName { get; set; }
public string BillingAddress { get; set; }
public string DeliveryName { get; set; }
public string DeliveryAddress { get; set; }
}
public class MOrder
{
public int ID { get; set; }
public int OrhID { get; set; }
public int ProID { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public double Rate { get; set; }
public double Amount { get; set; }
public int DeliveredQty { get; set; }
}
I would like to retrieve details from both classes. For example, I want to get
ID and Billing Name from class MorderMain and all the properties from class MOrder. How can I do this?
I am getting the values by database. I have the query but how will I assign the data and how will I retrieve from both?
var mylist = new List<MOrder>();
_con = _db.GetConnection();
if (_con.State.Equals(ConnectionState.Closed))
{
_con.Open();
}
_cmd = new SqlCommand("Get_All_Order_Details", _con)
{ CommandType = CommandType.StoredProcedure };
_dr = _cmd.ExecuteReader();
while (_dr.Read())
{
mylist.Add(new MOrder
{
ID = Convert.ToInt32(_dr["ordID"]),
OrhID = Convert.ToInt32(_dr["orhID"]),
ProID = Convert.ToInt32(_dr["proID"]),
Name = _dr["pName"].ToString(),
Quantity = Convert.ToInt32(_dr["ordQty"]),
Rate = Convert.ToDouble(_dr["ordRate"]),
Amount = Convert.ToDouble(_dr["ordAmount"]),
DeliveredQty = Convert.ToInt32(_dr["ordQtyDelivered"])
});
}
return mylist;
Since you are retrieving data from both tables in your database but want to combine them in your application, the solution would be to create a single class that contains the data you return from your stored procedure:
public class MAllOrderDetails
{
public int ID { get; set; }
public string BillingName { get; set; }
// include the other billing details you want here
public int OrhID { get; set; }
public int ProID { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public double Rate { get; set; }
public double Amount { get; set; }
public int DeliveredQty { get; set; }
}
Then, your query changes to filling in a List<MAllOrderDetails>.
This leaves your application with only dealing with a collection of a single class with all the data nicely contained in single objects.
var mylist = new List<MAllOrderDetails>();
//...
while (_dr.Read())
{
mylist.Add(new MAllOrderDetails
{
ID = Convert.ToInt32(_dr["ordID"]),
BillingName = _dr["BillingName"].ToString(),
// etc.
OrhID = Convert.ToInt32(_dr["orhID"]),
ProID = Convert.ToInt32(_dr["proID"]),
Name = _dr["pName"].ToString(),
Quantity = Convert.ToInt32(_dr["ordQty"]),
Rate = Convert.ToDouble(_dr["ordRate"]),
Amount = Convert.ToDouble(_dr["ordAmount"]),
DeliveredQty = Convert.ToInt32(_dr["ordQtyDelivered"])
});
}
Update
You could probably get away with this as the closest solution to not creating an additional classes:
class MAllOrderDetails
{
public MOrder Order { get; set; }
public MOrderMain OrderMain { get; set; }
}
I feel, though, that from a maintainability standpoint, this will cause you more headaches than just creating additional classes.

Categories

Resources