I Have the Following Model
ProductDetails.cs
public class ProductDetails
{
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ProductCodeID { get; set; }
public string CategoryName { get; set; }
public List<ProductDetails> lstProductDetails { get; set; }
}
Need to fill this model class with the query results that I'm getting from the DB
This is what I tried ..
var results = from a in db.ProductInfoes where productCodeID.Equals(productCodeID)
select new ProductDetails
{
ProductName = a.Product_Name.ToString(),
ProductCategoryID= a.Category_ID.ToString(),
ProductDescription = a.Product_Description.ToString()
};
What's the best way to update model class with query results?
you can try extending ProductInfoes and using automapper.
public **partial class** ProductInfoes {
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<AuthorModel, AuthorDTO>();
});
IMapper iMapper = config.CreateMapper();
public ProductDetails Map()
{
return iMapper.Map<ProductInfoes , ProductDetails>(this);
}
}
Remove the lstProductDetails property from the ProductDetails class.
to get all data (results will be of type: List<ProductDetails>)
var results = db.ProductInfoes
.Select(x => new ProductDetails()
{
ProductName = x.Product_Name.ToString(),
ProductCategoryID= x.Category_ID.ToString(),
ProductDescription = x.Product_Description.ToString()
}).ToList();
to get one record (result will be of type: ProductDetails):
var result = db.ProductInfoes.FirstOrDefault(x => x.productCodeID.Equals(productCodeID))
.Select(x => new ProductDetails()
{
ProductName = x.Product_Name.ToString(),
ProductCategoryID= x.Category_ID.ToString(),
ProductDescription = x.Product_Description.ToString()
};
(Add namespace System.Linq)
public ProductDetails getSelectedProductDetails(string productCodeID)
{
try
{
NaturesKingdomUKEntities db = new NaturesKingdomUKEntities();
List<ProductInfo> lst_ProductInfo = db.ProductInfoes.Where(x => x.Product_Code_ID.Equals(productCodeID)).ToList();
ProductDetails prd = new ProductDetails();
prd = lst_ProductInfo
.Where(y => y.Product_Code_ID.Equals(productCodeID))
.Select(x => new ProductDetails { ProductName = x.Product_Name, ProductCodeID = x.Product_Code_ID, UnitPrice=Convert.ToDouble(x.Unit_Price), ProductDescription=x.Product_Description, ProductAdditionalDescription=x.Product_Additional_Description, ProductType=x.Product_Type })
.FirstOrDefault();
return prd;
}
catch (Exception ex)
{
throw;
}
}
Finally it works with this way. Thanks a lot guys #Matt.G
Related
Product
public int Id { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public Category Category {get; set;}
Category
public int Id { get; set; }
public string CategoryName { get; set; }
public string CategoryDescription { get; set; }
public Product Product{get; set;}
ProductViewModel
public int Id { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public Category Category {get; set;}
Controller
public IActionResult GetProducts()
{
using var dbContext = new DatabaseContext();
var result = dbContext.Products.Where(i => i.Id == id)
.ThenInclude(i => i.Category)
.ToList();
List<ProductViewModel> productList = new List<ProductViewModel>();
foreach(var item in result)
{
var model = ProductViewModel()
{
Id = item.Id,
ProductName = item.ProductName,
ProductDescription = item.ProductDescription,
Category = new Category()
{
// Error: item.Category.CategoryName = 'item.Category.CategoryName' threw an
exception of type 'System.NullReferenceException'
CategoryName= item.Category.CategoryName,
CategoryDescription = item.Category.CategoryDescription,
Id = item.Category.Id
}
productList.Add(model);
}
}
How can I ignore null values in my DTO class.
I get my products from database.
Since the category is null in some products, I get an error when mapping it to my DTO class.
Use Select for projecting Model to DTO. It will create optimal SQL and should avoid loading unwanted data into the memory. Also EF should resolve nullability automatically.
public IActionResult GetProducts()
{
using var dbContext = new DatabaseContext();
var productList = dbContext.Products
.Where(i => i.Id == id)
.Select(item => new ProductViewModel
{
Id = item.Id,
ProductName = item.ProductName,
ProductDescription = item.ProductDescription,
Category = new Category
{
CategoryName = item.Category.CategoryName,
CategoryDescription = item.Category.CategoryDescription,
Id = item.Category.Id
}
})
.ToList();
...
}
Answer of #Svyatoslav Danyliv is the clean solution to your problem! However below my guess to your exception in your current solution.
I think it is because you are using ThenInclude. ThenInclude is usually used when you need to go into deeper includes.
Example: human --> head --> eye
dbContext.Humans.Include(x => x.Head).ThenInclude(x => x.Eye);
Your adjusted code:
var result = dbContext.Products.Include(i => i.Category).Where(i => i.Id == id).ToList();
Change ThenInclude with Include and give it a try! :)
Hello you can try using ??= operator which can protects you from null reference exception
using var dbContext = new A1APPsContext();
var result = dbContext.Products.Where(i => i.Id == id)
.Include(i => i.Category)
.ToList();
List<ProductViewModel> productList = new List<ProductViewModel>();
foreach (var item in result)
{
item.Category ??= new Category();
var model = new ProductViewModel()
{
Id = item.Id,
ProductName = item.ProductName,
ProductDescription = item.ProductDescription,
Category = new Category()
{
CategoryName = item.Category.CategoryName,
CategoryDescription = item.Category.CategoryDescription,
Id = item.Category.Id
}
};
productList.Add(model);
}
In that case you can also give a "No Category" category name and you will get it only when you dont have category by applying it in the class
public class Category
{
public int Id { get; set; }
public string CategoryName { get; set; } = "No Category";
public string CategoryDescription { get; set; }
public Product Product { get; set; }
}
Initially I was using automapper for this but its seems way harder for me to implement it.
Basically, I just want to return an empty list instead of null values. I can do this on projects level but not on teammates level. The API must not return a null because the UI that consumes it will have an error.
Sample of my implementation below:
Projects = !Util.IsNullOrEmpty(x.Projects) ? x.Projects : new List<ProjectsDto>(),
Ill highly appreciate if someone can guide me on how to manually map this with null/empty checking.
If you can also provide and example using automapper that too will be very helpful.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public List<ProjectsDto> Projects { get; set; }
}
public class ProjectsDto
{
public string Status { get; set; }
public List<TeammatesDto> Teammates { get; set; }
}
public class TeammatesDto
{
public string TeammateName { get; set; }
public string PreviousProject { get; set; }
}
//Get by Id
var employee = await _context.Employees
.Where(x => x.id.Equals(request.Id)
.FirstOrDefaultAsync(cancellationToken);
//Map employee
EmployeeDto ret = new EmployeeDto()
{
Id = employee.id,
Name = employee.Name,
Projects = null //TODO: map manually
}
//Get all employees
var employees = await _context.Employees.AsNoTracking()
.ToListAsync(cancellationToken);
//Map here
IList<EmployeeDto> list = new List<EmployeeDto>();
foreach (var x in employees)
{
EmployeeDto dto = new EmployeeDto()
{
Id = x.id,
Name = x.Name,
Projects = null //TODO: map manually
};
list.Add(dto);
}
return list;
Instead of materializing full entities, do the following:
var query = _context.Employees
.Select(e = new EmployeeDto
{
Id = e.id,
Name = e.Name,
Projects = e.Projects.Select(p => new ProjectDto
{
Status = p.Status,
Templates = p.Templates.Select(t => new TemplateDto
{
TeammateName = t.TeammateName,
PreviousProject = t.PreviousProject
}).ToList()
}).ToList()
}
);
var result = await query.ToListAsync();
How can I get a reference to the 'parent' object in the Linq below. Something like the way EF does it when you query for objects that are of EF Classes?
void Main()
{
IEnumerable<SomeModel> Brands = ....;
var list = Brands
.Select(b => new BrandModel()
{
ID = b.ID,
BrandName = b.Name,
Locations = b.Locations.Select(l => new LocationModel()
{
ID = l.ID,
LocationName = l.Name,
Brand = *here I would want the Brand object of this Location*
}).ToList()
}).ToList();
}
private class BrandModel
{
public int ID { get; set; }
public string BrandName { get; set; }
public List<LocationModel> Locations { get; set; }
}
private class LocationModel
{
public int ID { get; set; }
public string LocationName { get; set; }
public BrandModel Brand { get; set; }
}
You can create your BrandModel in two steps. First create it without locations, then set locations to it
To do so you need to convert your lambda b => new BrandModel() to block of statements b => { return new BrandModel() }. Try this code:
.Select(b =>
{
var model = new BrandModel
{
ID = b.ID,
BrandName = b.Name
};
model.Locations = b.Locations.Select(l => new LocationModel
{
Brand = model
}).ToList();
return model;
});
I am trying to fill a list with my categories data.
My categories have cascade format. They are formatted recursively in my database.
Here is my model object.
public class CategoriesDTO
{
public int Id { get; set; }
public int Level { get; set; }
public string Name { get; set; }
public List<CategoriesDTO> Subs { get; set; }
}
So, in my business layer, i am trying to call this method like this:
DAO.Categories(0);
it will start with "Level==0" condition and then it will go on..
but i couldn't manage the Data Access Layer. I tried this:
public List<CategoriesDTO> Categories(int PrmLevel)
{
List<CategoriesDTO> DTO = new List<CategoriesDTO>();
//DB is my dbcontext.
DTO = DB.Categories.Select(x => new CategoriesDTO()
{
Id = x.Id,
Level = x.Level,
Name = x.Name
}).Where(y => y.Level == PrmLevel).ToList();
foreach (var item in DTO)
{
//im stucked
}
return DTO;
}
}
public List<CategoriesDTO> Categories(int PrmLevel)
{
List<CategoriesDTO> DTO = new List<CategoriesDTO>();
//DB is my dbcontext.
DTO = DB.Categories.Select(x => new CategoriesDTO()
{
Id = x.Id,
Level = x.Level,
Name = x.Name
}).Where(y => y.Level == PrmLevel).ToList();
foreach (var item in DTO)
{
item.Subs = ((PrmLevel + 1) <= MaxLevel) ? Categories(PrmLevel + 1) : null;
}
return DTO;
}
}
public List<CategoriesDTO> Categories(int PrmLevel)
{
List<CategoriesDTO> DTO = new List<CategoriesDTO>();
//DB is my dbcontext.
DTO = DB.Categories.Select(x => new CategoriesDTO()
{
Id = x.Id,
Level = x.Level,
Name = x.Name
}).Where(y => y.Level == PrmLevel).ToList();
foreach (var item in DTO)
{
int CountSub = 0;
CountSub = DB.Categories.Where(x => x.Level == item.Id).ToList().Count();
if (CountSub!=0)
{
item.Subs = Categories(item.Id).ToList();
}
}
return DTO;
}
}
I'm sure someone else has asked this but I searched on what I could think of to find the solution.
I've got the following data models to match tables in my SQL db:
public class ProfileDetailModel
{
public string id { get; set; }
public string name { get; set; }
public StyleList[] styleList { get; set; }
public FabricList[] fabricList { get; set; }
}
public class StyleList
{
public string id { get; set; }
public string name { get; set; }
}
public class FabricList
{
public string id { get; set; }
public string fabricName { get; set; }
}
This is the current query code:
var query = (from t in db.tblProfiles
select new ProfileDetailModel()
{
id = t.id,
name = t.name
});
var querylist = await query.ToListAsync();
(prototyped linq queries below for style and fabric)
var styleQuery = (from t in db.tblStyles
select new styleList()
{
id = t.id,
name = t.name
});
var fabricQuery = (from t in db.tblFabrics
select new fabricList()
{
id = t.id,
name = t.name
});
if (queryList.Count > 0)
{
var item = queryList[0];
item.styleList = styleQuery;
item.fabricList = fabricQuery;
}
I'll have one profileDetailModel with multiple items in styleList and in fabricList. EG.
ProfileDetailModel
Data: Pants
styleList: Bell Bottom, Straight Leg, Boot fit
fabricList: jean-blue, jean-black, plaid
All three above models are tables in my db. I could issue 3 separate queries to read the data then assemble after the fact. But is there a way I can do a linq query to include the two arrays in the main query in one shot?
Try this:
var newQuery = (from p in db.tblProfiles
select p)
.AsEnumerable()
.Select(x => new ProfileDetailModel()
{
id = x.id,
name = x.name,
styleList = styleQuery,
fabricList = fabricQuery
});