Entity framework to populate a ViewModel - linq

I'm not sure where to start doing this with entity framework. Here are samples of the table data. The tables are created via code first.
I have 5 tables:
Id - Person
12 - John
13 - Sarah
14 - Bob
15 - Frank
Id - Package
1 - Standard
2 - Extra
3 - Gold
4 - Off Season
Id - Features
21 - Feature A
22 - Feature B
23 - Feature C
24 - Feature D
Link Tables
PersonId - PackageId
12 - 1
12 - 4
13 - 3
14 - 2
15 - 1
15 - 2
PackageId - FeatureId
1 - 21
1 - 22
2 - 21
2 - 22
2 - 23
3 - 21
I know that I can find out a Person's Features like this:
var person = _db.Persons
.Where(p => p.Id == id)
.Include(p => p.Packages)
.Include("Packages.Features")
.SingleOrDefault();
However I would like to get a ViewModel class or even a list that has only these columns:
PersonId Person FeatureId Feature
12 - John - 21 - Feature A
12 - John - 22 - Feature B
I know I can do it with SQL. I'm just not sure how to do it with Linq and Entity Framework. What's the best practice to do that?

I would recommend using EF Code First.
You can create the following classes:
public class Person
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
...
public ICollection<Package> Packages { get; set; }
}
public class Package
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
...
public ICollection<Feature> Features { get; set; }
}
public class Feature
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
...
}
Then you could create a ViewModel like this:
public class PersonViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
...
public List<FeatureViewModel> Features { get; set; }
}
You can get the data using LINQ To Entities like this:
var person = _db.Persons
.Where(p => p.Id == id)
.Include(p => p.Packages)
.Include("Packages.Features")
.SingleOrDefault();
And to fill the ViewModel using Automapper for example:
var personViewModel = Mapper.Map<PersonViewModel>(person);

Related

LINQ from a list inside a class

I have the following Model class:
public partial class EmployeeInfo
{
public int EmployeeInfoId { get; set; }
public string FirstName { get; set; } = null!;
public int? JobTitleLookupId { get; set; }
public virtual JobTitleLookup? JobTitleLookup { get; set; }
}
public partial class JobTitleLookup
{
public int JobTitleLookupId { get; set; }
public string Title { get; set; } = null!;
public virtual ICollection<EmployeeInfo> EmployeeInfos { get; } = new List<EmployeeInfo>();
}
I have JobTitleLookupId in my employeeeInfo database table. How can i get the name of the jobtitle if i have the corresponding ID in employeeInfo Table.
below is my JobTitleLookup table:
JobTitleLookupID title
1 title1
2 title2
3 title3
EmployeeInfo table
EmployeeInfoId FirstName JobTitleLookupID
1 test1 2
2 test3 1
3 testx 3
How can I get the job title if I have the employeeinfoId and jobTitleLookupID using LINQ.'
this is what I tried so far:
public async Task<List<string?> GetJobTitle(string employeeId)
{
var query = _ackContext.EmployeeInfos
.Include(c => c.JobTitleLookup)
.Where(c => c.EmployeeNumber == employeeId)
}
this is something I wrote in sql. I want the same in LINQ
SELECT
title
FROM
employeeInfo e
INNER JOIN JobTitleLookup j ON
e.JobTitleLookupID =j.JobTitleLookupID
AND
EmployeeInfoID = 212;
To select something precise, you have to use Select.
public Task<List<string?> GetJobTitle(string employeeId)
{
return _ackContext.EmployeeInfos
.Where(c => c.EmployeeNumber == employeeId)
.Select(c => c.JobTitleLookup.Title)
.ToListAsync();
}

EF Core non-existant column in query, how to rectify?

working my way through an EF core project I have inherited and am quite new when it comes to LINQ/EF core.
I'll cut this back to simplify things, and will demonstrate my problem with 4 basic tables.
Customer
CustomerId
Name
Contact
1
John
john#gmail.com
2
Peter
peter#gmail.com
CustomerTrade
Id
CustomerId
OtherDetail
T1
1
xyz
T2
1
abc
CustomerTradeParameter
ParamID
TradeId
Value
X
1
1234
Y
1
5678
CustomerTradeParameterType
ParamID
Name
OtherGenericInfo
X
Hello
Null
Y
Test
Null
Models
public class Customer : AuditableEntity
{
public long CustomerId { get; private set; }
public string Name { get; private set; }
public string Contact { get; private set; }
public virtual ICollection<CustomerTrade> CustomerTradeList{ get; set; }
protected Customer()
{ }
public class CustomerTrade : AuditableEntity
{
public long Id { get; private set; }
public long CustomerId { get; private set; }
public string OtherDetail { get; private set; }
public virtual ICollection<CustomerTradeParameter> CustomerTradeParameterList { get; set; } = new List<CustomerTradeParameter>();
protected CustomerTrade() // For EF Core
{ }
public class CustomerTradeParameter : AuditableEntity
{
public long TradeId { get; set; }
public string ParameterType { get; private set; }
public string Value{ get; private set; }
protected CustomerTradeParameter() // For EF Core
{ }
}
DTOs
public class CustomerTradeDto : AuditableDto
{
public long Id { get; set; }
public long CustomerId { get; set; }
public virtual ICollection<CustomerTradeParameterDto> CustomerTradeParameterList { get; set; } = new List<CustomerTradeParameterDto>();
}
public class CustomerTradeParameterDto : AuditableDto
{
public long TradeId { get; set; }
public string ParameterType { get; set; }
public string Value { get; set; }
}
The below query is attempting to retrieve a specific trade, and a list of its relevant parameters.
IQueryable<CustomerTradeDto> foundTrade = _database.CustomerTrade
.Select(trade => new CustomerTradeDto
{
Id = trade.Id,
CustomerId = trade.CustomerId,
CustomerTradeParameterList = trade.CustomerTradeParameterList.Select(param => new CustomerTradeParameterDto{
ParameterType = param.ParameterType,
TradeId = customerTrade.Id,
Value = param.Value
// (second question written further below) - If I wanted to additionally retrieve the CustomerTradeParameterType record
// (to get the name of this parameter), how would I embed this join?
// I originally had ParameterType defined as a "CustomerTradeParameterType" instead of a string,
// but am not sure how to add this extra join inside this select?
}).ToList()
})
.Where(e => e.Id == find.Id);
The .Select on CustomerTradeParameterList is raising the following error:
Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid column name 'CustomerTradeId'.
I understand EF core is attempting to define a column that it is unsure of, but I am not sure how to fix this? The correct column is TradeId.
Secondly, I have an additional question regarding joins inside a sub .Select. In the query above I have a comment outlining the question.
Appreciate any tips you can provide!

How to display data from two master and child table based upon a condition

I have two tables Category(Master),Products(child). I want to combine them and get some data and display it
public partial class Product
{
public int Product_Id { get; set; }
public string Product_Name { get; set; }
public Nullable<int> Regular_Price { get; set; }
public Nullable<int> Category_Id { get; set; }
}
public partial class Category
{
public int Category_Id { get; set; }
public string Category_Name { get; set; }
}
//A viewmodel as
public class ViewModel
{
public IEnumerable<Product> Product { get; set; }
public Category Category { get; set; }
}
And I have the data as
Product_Id Product_Name Price Category_Id
1 a1 5000 10
2 a2 5700 10
3 a3 5000 10
4 a4 5000 10
5 b1 1000 20
6 b2 2000 20
7 c1 4000 30
8 c2 7000 30
Category_Id Category_Name
10 A
20 B
30 C
40 D
Here my requirement is I want something like
#foreach(var item in model
{
//Required code
}
A
a1
a2
a3
a4
B
b1
b2
C
c1
c2
Is the ViewModel proper or do I require changes in it.
Thanks
Based on your output(what you have shown) your ViewModel should like:-
public class ViewModel
{
public IEnumerable<string> ProductName { get; set; }
public string CategoryName{ get; set; }
}
Since You are intrested in CategoryName & its respective ProductName, You can use group join like this:-
List<ViewModel> result = (from c in category
join p in products
on c.Category_Id equals p.Category_Id into g
select new ViewModel
{
CategoryName = c.Category_Name,
ProductName = g.Select(x => x.Product_Name)
}).ToList();
If you want to fetch complete Product object then simply change your ViewModel like this:-
public class ViewModel
{
public IEnumerable<Product> Product { get; set; }
public string CategoryName { get; set; }
}
And select the complete Product from query:-
//Rest of the query
select new ViewModel
{
CategoryName = c.Category_Name,
Product = g
}).ToList();
In your View you can use foreach loop to show the results, here is the complete Working Fiddle.

How can i write a linq query for multiple tables in entity model MVC4?

I have these tables in my entity model
dbo.Options
[OptionsId] [OptionName]
1 Color
2 Size
3 Fit
dbo.ProductAttributes:
[ProdcutAttributeId] [SKU] [OptionId] [Value]
3001 Shirt_1001 1 Grey
3002 Shirt_1001 2 S
3003 Shirt_1001 3 Regular
3004 Shirt_1002 1 Black
3005 Shirt_1002 2 M
3006 Shirt_1002 3 Slim
dbo.Products:
[ProductId [ProductName] [ProductDescription] [Stock] [ImageURL] [ProductType]
dbo.ProductSKU:
ID SKU ProductId Price ImageURL
2001 Shirt_1001 1001 12 C:\Users\Administrator\Desktop\Images\LongSleeveShirt.jpg
2002 Shirt_1002 1001 13 C:\Users\Administrator\Desktop\Images\LongSleeveShirtBlack.jpg
2003 Shirt_1003 1001 12 C:\Users\Administrator\Desktop\Images\LongSleeveShirtkhaki.jpg
2004 Shirt_1004 1001 13 C:\Users\Administrator\Desktop\Images\LongSleeveShirtOrange.jpg
2005 Tshirt_1001 1002 13 C:\Users\Administrator\Desktop\Images\PlainWhiteT.jpg
2006 Tshirt_1002 1002 12 C:\Users\Administrator\Desktop\Images\PrintedTBlue.jpg
2007 Tshirt_1003 1002 13 C:\Users\Administrator\Desktop\Images\PrintedTWhite.jpg
2008 Tshirt_1004 1002 12 C:\Users\Administrator\Desktop\Images\LongSleeveBlackT.jpg
So these are the table I have in my entity model, now I want to write a linq query where I will pass the productID as parameter and I should get the productid,productname,productdescription of the productid passed as a parameter, and every Sku that product has each option the sku has and imageURl of the SKU.
How can I write a linq query for this?
this is how my model looks
public class ProductItems
{
public long ProductID { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ImageURL { get; set; }
public string SKU { get; set; }
public long OptionID { get; set; }
public string optionName { get; set; }
public string Value{ get; set; }
public ProductItems()
{
if (SKUs == null )
SKUs = new List<productSKU>();
}
public List<productSKU> SKUs { get; set; }
public List<options> oPTIONS { get; set; }
}
public class productSKU
{
public productSKU()
{
if (oPTIONS == null)
oPTIONS = new List<options>();
}
public string productsku { get; set;}
public string SKUImageURL { get; set;}
public List<options> oPTIONS { get; set; }
}
public class options
{
public long OptionID { get; set; }
public string OptionName { get; set;}
public string OptionValue { get; set;}
}
Now I want to bind prodcuname,description and prodid to ProductItems class and every sku details should be bound to ProductSku class and each SKuOption should be bound to options class
I should get these columns at last [ProductID ],[ProductName ],[ProductDescription ],[SKU],[OptionId],[OptionName],[Value],[ImageURL] at last what I need is ProductName,Description every SKU of the product,every option value and name of the product
this is waht i am trying to do but i am confused how to bind this to my model
var produ = from PS in products.ProductSKUs
join PA in products.ProductAttributes on PS.SKU equals PA.SKU
join p in products.Products on PS.ProductId equals p.ProductId
join o in products.Options on PA.OptionId equals o.OptionsId
where PS.ProductId==ID
select new ProductItems()
{
ProductID=p.ProductId,
ProductName=p.ProductName,
ProductDescription = p.ProductDescription,
i am stuck here what to do next from here can any one help me here or provide me soltuion will be much gratefull
Thanks to any one who tried to answer my question i worked on this and got the solution
any one who wants to refer this i am posting the solution here
private ProductEntities products = new ProductEntities();
public IEnumerable<ProductItems> GetProductDetail(long ID)
{
ProductItems items=new ProductItems();
List<ProductItems> objcollection=new List<ProductItems>();
var productdetail=from prod in products.Products where prod.ProductId==ID select new {productid=prod.ProductId,description=prod.ProductDescription,productname=prod.ProductName};
foreach(var detail in productdetail)
{
items.ProductID=detail.productid;
items.ProductName=detail.productname;
items.ProductDescription=detail.description;
var prodsku=from prodksu in products.ProductSKUs where prodksu.ProductId==ID select prodksu;
foreach(var sku in prodsku)
{
productSKU prdsk=new productSKU();
prdsk.productsku=sku.SKU;
prdsk.SKUImageURL=sku.ImageURL;
items.SKUs.Add(prdsk);
var opt = from PA in products.ProductAttributes
join O in products.Options on PA.OptionId equals O.OptionsId
where PA.SKU == prdsk.productsku
select new { OptionId = PA.OptionId, OptionValue = PA.Value, OptionName = O.OptionName };
foreach(var op in opt)
{
options obj=new options();
obj.OptionID=Convert.ToInt16(op.OptionId);
obj.OptionName = op.OptionName;
obj.OptionValue=op.OptionValue;
prdsk.oPTIONS.Add(obj);
}
objcollection.Add(items);
}
}
return objcollection;
}

Complex LINQ or EF query

I have the following 3 classes.
A workflow configuration has one brand and one workflowtype.
I need one method in linq or EF that gets me all the brands of existing workflowconfiguration and another method that gets me all the brands of non existing workflow configuration.
I am lost cause I dont know where to start.
public class Brand
{
public int BrandId { get; set; }
public string Name { get; set; }
}
public class WorkflowType
{
public int WorkflowTypeId { get; set; }
public string Name { get; set; }
}
public class WorkflowConfiguration
{
public int WorkflowConfigurationId { get; set; }
public WorkflowType WorkflowType { get; set; }
public Brand Brand { get; set; }
public virtual ICollection<Approver> Approvers { get; set; }
}
Update1
Here are how my tables would look like and the expected result
Brand
Audi
Volkswagen
Mercedes
WorkflowTYpes
type 1
type 2
type 3
WorkflowConfiguration
brandid, workflowtype id
1 ------------ 1
1 -------------2
List<string> GetBrandsForExistingWorkflowType(string worfklowtype)
If I pass type1 to this method it should return:
Audi because for type1, audi exists on the table
List<string> GetBrandsForNonExistingWorkflowType(string workflowType)
If I pass type1 to this method it should return.
Volkswagen and Mercedes because for type1, those 2 brands are not in the relationship.
I think this is what you want:
List<string> GetBrandsForExistingWorkflowType(string worfklowtype)
{
var result = db.WorkflowConfigurations
.Where(x => x.WorkflowType.Name == worfklowtype)
.Select(x => x.Brand);
return result;
}
List<string> GetBrandsForNonExistingWorkflowType(string workflowType)
{
var excluded = GetBrandsForExistingWorkflowType(string worfklowtype);
var result = db.Brands.Except(excluded);
return result;
}

Resources