Join multiple one to many related tables in EF and select as view model - entity-framework

Database Models of my Application are:
public class Restaurant
{
public int Id { get; set; }
.........
}
public class Review
{
public int Id { get; set; }
public string ReviewTitle { get; set; }
public string ReviewContent { get; set; }
public int UserId { get; set; }
public int RestaurantId { get; set; }
}
public ReviewHelpful
{
public int Id { get; set; }
public int ReviewId { get; set; }
public bool IsHelpfull { get; set; }
}
public ReviewImage
{
public int Id { get; set; }
public string ImageLink { get; set; }
public int ReviewId { get; set; }
}
There is no navigation property in any table. In ReviewHelpful table, If user finds helpfull of this review than value is true otherwise false.
Now I want to create a view-model Like this:
public class ReviewViewModel
{
public int ReviewId { get; set; }
public int RestaurantId { get; set; }
public string ReviewTitle { get; set; }
public string ReviewContent { get; set; }
public int UserId { get; set; }
public int NumberOfHelpfull { get; set; }
public int NumberOfNotHelpfull { get; set; }
public List<string> ImagesLinks { get; set; }
}
For that reason, I want to write this kind of query :
var reviews = (from review in _foodTrackerContext.RestaurantReviews
join helpful in _foodTrackerContext.Helpfuls on review.Id equals helpful.ReviewId
join reviewPicture in _foodTrackerContext.ReviewPictures on review.Id equals reviewPicture.ReviewId
where review.ResturantId == 2
select new ReviewViewModel()
{
Id = review.Id,
RestaurantId = 2,
ReviewTitle = review.ReviewTitle,
ReviewContent = review.ReviewContent,
NumberOfHelpfull = .. ??,
NumberOfNotHelpfull = ... ??,
ImagesLinks = ... ???
}
I can not retrieve HelpfulYes, HelpfulNo, ImagesLinks with this query. What would be query for finding these variables?.
This query produces multiple rows for single review with each ReviewImage and each ReviewHelpful.

The query that ypu need to do is this one:
var model =
from review in ctx.Reviews
where review.RestaurantId == 2
join helpful in ctx.ReviewHelpfuls
on review.Id equals helpful.ReviewId into helpfuls
join image in ctx.ReviewImages
on review.Id equals image.ReviewId into images
select new RestaurantReviewViewModel
{
Id = review.Id,
RestaurantId = 2,
ReviewTitle = review.ReviewTitle,
ReviewContent = review.ReviewContent,
NumberOfHelpfull = helpfuls.Count(h => h.IsHelpfull),
NumberOfNotHelpfull = helpfuls.Count(h => !h.IsHelpfull),
ImagesLinks = (from image in images select image.ImageLink).ToList()
};
Please, note that when you do a one to manyh join you need to include an into to give a nameto the joined entities to be able to work on them.
I've used the dot syntax for selecting the count, but you could use the query syntax if you wanted. Over time, I've found dot synatx more natural.
NOTE: if you used navigation properties this would become much easier. Why are you not using them? With navigation properties you don't need to make the joins explicitly, as they are already available.

List<ReviewViewModel> listModel = new List<ReviewViewModel>();
context.dbRestaurant
.include("Review")
.include("Review.ReviewHelpful")
.include("Review.ReviewImage").ToList().ForEach((item) =>
{
ReviewViewModel model = new ReviewViewModel();
model.ID = item.ID
listModel.Add(model);
});

Related

Method based linq queries

I have five tables in database whose Entity classes are as follows -
Product
public int ProductId { get; set; }
public string Name { get; set; }
public int Category { get; set; }
public string Description { get; set; }
public string Brand { get; set; }
public virtual ProductCategory ProductCategory { get; set; }
public virtual ICollection<ProductImage> ProductImages { get; set; }
public virtual ICollection<ProductVariantMapping> ProductVariantMappings
ProductCategory
public int CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
ProductImage
public int ProductImageId { get; set; }
public int ProductId { get; set; }
public byte[] Image { get; set; }
public virtual Product Product { get; set; }
ProductVariantMapping
public int MappingId { get; set; }
public int ProductId { get; set; }
public int ProductVariantId { get; set; }
public string Value { get; set; }
public System.Guid GUID { get; set; }
public virtual Product Product { get; set; }
public virtual ProductVariant ProductVariant { get; set; }
ProductVariant
public int ProductVariantId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<ProductVariantMapping> ProductVariantMappings
I want to get Product Details which should include ProductId, ProductName, Category, Description, Brand, Image(Only 1 for now), and Variants*
*Variants would be a list of all the variants of a product. A single variant can be a combination of all the VariantIds with same GUIDs. (VariantName is in ProductVariant table and VariantValue is in ProductVariantMapping table and Price is in inventory table).
So, I used method-based linq for this purpose.
EkartEntities ekartEntities = new EkartEntities();
var productDetails = ekartEntities.Products.Include(p =>
p.ProductVariantMappings).Include(p => p.ProductImages).Include(p =>
p.ProductCategory).Where(p => p.ProductId ==
productDetailDTO.ProductId).ToList();
Now I have to convert my product into a ProductDetailDTO.
ProductDetailDTO
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 List<Variant> Variants { get; set; }
}
public class Variant
{
public string Name { get; set; }
public string Value { get; set; }
public System.Guid Guid { get; set; }
public decimal Price { get; set; }
}
I started doing this like this -
void ToDTO(List<Product> products)
{
EkartEntities ekartEntities = new EkartEntities();
ProductDetailDTO productDetailDTO = new ProductDetailDTO();
foreach (var item in products)
{
productDetailDTO.ProductId = item.ProductId;
productDetailDTO.Name = item.Name;
productDetailDTO.Category = item.ProductCategory.Name;
productDetailDTO.Description = item.Description;
productDetailDTO.Brand = item.Brand;
productDetailDTO.Image = item.ProductImages.ElementAt(0).Image;
foreach (var variant in item.ProductVariantMappings)
{
productDetailDTO.Variants = variant.ProductVariant // ?
}
}
}
I don't know how do I proceed further. How can I extract the variant based on the GUIDs?
The logic of combining of ProductVariant entries with same GUID in mapping table doesn't seem clear from the question, however you can group entries in ProductVariantMappings by GUID and then add any logc you like on group. Here is an example where I take first name and value in a groub of variant with the same GUID:
void ToDTO(List<Product> products)
{
EkartEntities ekartEntities = new EkartEntities();
ProductDetailDTO productDetailDTO = new ProductDetailDTO();
foreach (var item in products)
{
productDetailDTO.ProductId = item.ProductId;
productDetailDTO.Name = item.Name;
productDetailDTO.Category = item.ProductCategory.Name;
productDetailDTO.Description = item.Description;
productDetailDTO.Brand = item.Brand;
productDetailDTO.Image = item.ProductImages.ElementAt(0).Image;
productDetailDTO.Variants = item.ProductVariantMappings
.GroupBy(pm => pm.GUID)
.Select(g => new Variant
{
Guid = g.Key,
// Here should be some logic for getting a name of the combination of Variants
// I just take first
Name = g.FirstOrDefault()?.ProductVariant?.Name,
// Here should be some logic for getting a value of the combination of Variants
// Take first again
Value = g.FirstOrDefault()?.Value,
Price = // need inventory table to compute price
})
.ToList();
}
}
Also note that you need somehow add relation to inventory table, which is not presented in question. Hope it helps.

How to create Model based C# List from Database

I have Models created through Entity Framework as:
public partial class Order
{
public Order()
{
this.OrderDetails = new HashSet<OrderDetail>();
}
public int OrderID { get; set; }
public string OrderNo { get; set; }
public System.DateTime OrderDate { get; set; }
public string Description { get; set; }
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
}
Then another Details Table:
public partial class OrderDetail
{
public int OrderItemsID { get; set; }
public int OrderID { get; set; }
public string ItemName { get; set; }
public int Quantity { get; set; }
public decimal Rate { get; set; }
public decimal TotalAmount { get; set; }
public virtual Order Order { get; set; }
}
To See the Master Detail Data I made MasterDetails model As:
public class OrderVM
{
public string OrderNo { get; set; }
public DateTime OrderDate { get; set; }
public string Description { get; set; }
public List<OrderDetail> OrderDetails {get;set;}
}
I'm trying to make a method that return a LIST with Join query results but
I'm receiving #Anonymous type error here is my Code:
public static List<OrderVM > mylist()
{
List<OrderVM> slist = new List<OrderVM>();
using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
{
var myvalues = from O in dc.Orders
join D in dc.OrderDetails
on
O.OrderID equals D.OrderID
select new
{
O.OrderID,
O.OrderDate,
D.Quantity,
D.Rate
};
foreach(var myorders in myvalues)
{
slist.Add(myorders);
}
return slist;
}
}
I need a help that how I can I create a generic list with database fields
Create new class:
public class OrderDetailsModel
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public int Quantity { get; set; }
public decimal Rate { get; set; }
}
and return list of objects of this class from your method:
using (MyDatabaseEntities1 dc = new MyDatabaseEntities1())
{
var myvalues = from O in dc.Orders
join D in dc.OrderDetails
on
O.OrderID equals D.OrderID
select new OrderDetailsModel
{
OrderId = O.OrderID,
OrderDate = O.OrderDate,
Quantity = D.Quantity,
Rate = D.Rate
};
return myvalues.ToList();
}

Entity Framework 6 (code first) using child collection foreign key without the parents primary key

I really think I am missing something here that's probably really simple that's not jumping out at me.
I have these objects and I am trying to join a parent object to a child collection but not necessarily using the parent's primary key. In sql I can do this pretty easily, but it's bugging me why this cannot happen using code first. I am trying to join CompetitorMatchInformation to BrandSkuPricing by the ErpSkuId.
public class CompetitorMatchInformation {
[Key(), Column("MatchId")]
public long MatchId { get; set; }
[Column("ErpSkuId")]
public int? ErpSkuId { get; set; }
[Column("CompetitorId")]
public int CompetitorId { get; set; }
[ForeignKey("CompetitorId")]
public virtual Competitors Competitor { get; set; }
[ForeignKey("CompetitorItemToErpSkuMatchId")]
//[ForeignKey("ErpSkuId")]
public virtual List<BrandSkuPricing> BrandSkuPricing { get; set; }
}
public class Competitors
{
[Key(), Column("CompetitorId")]
public int CompetitorId { get; set; }
[Column("CompetitorName")]
public string CompetitorName { get; set; }
}
public class BrandSkuPricing
{
[Key(), Column("BrandSkuId")]
public int BrandSkuId { get; set; }
[Column("CompetitorItemToErpSkuMatchId")]
public long CompetitorItemToErpSkuMatchId { get; set; }
[Column("ErpSkuId")]
public int? ErpSkuId { get; set; }
[Column("Price")]
public decimal? Price { get; set; }
[Column("BrandId")]
public int? BrandId { get; set; }
[Column("BrandSourceSytemId")]
public string BrandSourceSytemId { get; set; }
[Column("BrandName")]
public string BrandName { get; set; }
[Column("BrandSkuNumber")]
public string BrandSkuNumber { get; set; }
}
The Competitor comes over correctly, but the child collection not so much. This isn't a normal scenario I know, but the underlying view for BrandSkuPricing has a relationship that's not entirely normal.
The query I am using is
public List<CompetitorMatchInformation> GetCompetitorMatchInfoByCompetitorItemId(long competitorItemId, int? brandId = null)
{
var query = this.Entity.Include(x => x.CurrentChallenges).Include(x => x.BrandSkuPricing);
var list = query.Where(x => x.CompetitorItemId == competitorItemId &&
((x.CurrentChallenges.Count > 0 && x.CurrentChallenges.Any(w => !w.IsResolved)) ||
x.CurrentChallenges.Count == 0))
.ToList();
list.ForEach(l =>
{
if (brandId.HasValue)
{
l.BrandSkuPricing = l.BrandSkuPricing.Where(x => x.BrandId == brandId).ToList();
}
});
return list;
}
And in the model builder, I have nothing. I have tried but cannot get it to work even in the builder. Anyway I can get the child collection to join on ErpSkuId? I have changed the underlying view to pull in the CompetitorItemToErpSkuMatchId so it working that way, but this scenario of joining on something that isn't a key will come up for me a lot soon.
Thanks!

Get multiple tables data through Entity Framework with Generic Repository and Unit Of work

I am working on Web-API project and using Entity Framework with Generic Repository and Unit Of work. Basically i follow a tutorial for this.
Here is my table architecture.
Entity
public class ProductEntity
{
public int ProductId { get; set; }
public string ProductCode { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ProductImgName { get; set; }
public bool IsActive { get; set; }
public int PrimaryCatId { get; set; }
public int SecondaryCatId { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public System.DateTime CreateDate { get; set; }
public List<PrimaryProductEntity> objPrimaryProduct { get; set; }
public List<SecondaryProductEntity> objSecondaryProduct { get; set; }
}
public class PrimaryProductEntity
{
public int PrimaryCatId { get; set; }
public string PrimaryCatName { get; set; }
}
public class SecondaryProductEntity
{
public int SecondaryCatId { get; set; }
public string SecondaryCatName { get; set; }
public int PrimaryCatId { get; set; }
}
Services Code
public IEnumerable<BusinessEntities.ProductEntity> GetAllProducts()
{
var products = _unitOfWork.ProductRepository.GetAll().ToList();
var primaryProducts = _unitOfWork.PrimaryProductRepository.GetAll().ToList();
var secondaryProducts = _unitOfWork.SecondaryProductRepository.GetAll().ToList();
if (products.Any())
{
Mapper.CreateMap<tblProduct, ProductEntity>();
var proInfo = from P in products
join PP in primaryProducts on P.PrimaryCatId equals PP.PrimaryCatId
join SP in primaryProducts on P.SecondaryCatId equals SP.SecondaryCatId
select P;
var productsModel = Mapper.Map<List<tblProduct>, List<ProductEntity>>(proInfo);//getting error
return productsModel;
}
return null;
}
i know my implementation is wrong, i don't know what to write in code for fetch data from multiple tables. Please help me.
Required Data
ProductID,ProductName, PrimaryCatName, SecondaryCatName,Price, Quantity
Your Product Entity class Doesn't require a List<PrimaryProductEntity> and List<SecondaryProductEntity>. I suppose according to your class diagram Each Product is associated with one PrimaryProductEntity and one SecondaryProductEntity.
Once your model class is corrected, you would be able to access the properties of the navigation. I am not so good with writing a Query the way you want. But i hope you could get an idea of what you should be doing

EF 4 CTP 5 Complex query

I have a model like the following:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public DateTime DateTime { get; set; }
public Customer Customer { get; set; }
public ICollection<OrderLine> OrderLines { get; set; }
}
public class OrderLine
{
public int Id { get; set; }
public Product Product { get; set; }
public int Price { get; set; }
public int Quantity { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
I am using this infrastructure.
My aggregate roots are Customer, Order, Product. I did not include the mappings here as they are straight forward.
var customers = unitOfWork.Customers.FindAll();
var orders = unitOfWork.Orders.FindAll();
var products = unitOfWork.Products.FindAll();
var query = ......
Using LINQ, how would you select all customers that have orders for products in the "Beverages" category?
All samples I have seen on the web are very basic queries nothing advanced.
i found http://msdn.microsoft.com/en-us/vbasic/bb737909
May be your query should look like:
from c in unitOfWork.Customers
join o in unitOfWork.Orders on o.Customer = c
join ol in unitOfWork.OrderLines on ol.Order = o
where ol.Product.Category.Name == "Beverages"
select c
And it is necessary to add all parent-object-properties
This might work or not:
from customer in customers
where customer.Orders.Any(
o => o.OrderLines.Any(l => l.Product.Category.Name == "Beverages")
select customer
(I'm assuming you forgot the relationship between Product and Category)