Grouping in linq in EF Core - c#

I have the following data:
ImagesTable:
Id Name CategoryId
1 image1 1
2 image2 1
CategoryTable:
Id CategoryName Description
1 Team Building TB 2020
I am writing a query in linq to get all the category of images and the associated images within each category.
var query = from p in _context.ImagesCategory
join s in _context.ImagesGallery on p.Id equals s.CategoryId into groupcat
from s in groupcat
select new CategoryGalleryDto { Id = p.Id, CategoryName = p.ImageCategory, CategoryDescription = p.ImageDescription, ImagesList = new List<ImageGalleryDto> { new ImageGalleryDto { ImageName = s.ImageName } } };
var grouping = query.ToLookup(e => e.Id).ToList();
My query is returning me three categories despite I have only one category. Please help
My DTOS
public class CategoryGalleryDto
{
public int Id { get; set; }
public string CategoryName { get; set; }
public string CategoryDescription { get; set; }
public DateTime UploadedDate { get; set; }
public List<ImageGalleryDto> ImagesList { get; set; }
}
public class ImageGalleryDto
{
public int Id { get; set; }
public string ImageName { get; set; }
public int CategoryId { get; set; }
}

Related

EF Core 5 single property projection

I want to reduce duplicated code. In order to achieve that I want to reference the projections of my Entities.
Entities
public class Category
{
public string Id { get; set; }
public string CategoryName { get; set; }
public static Expression<Func<Category, Category>> Proj() => c => new Category
{
CategoryName = c.CategoryName
};
}
public class Image
{
public string Id { get; set; }
public string Url { get; set; }
public static Expression<Func<Image, Image>> Proj() => i => new Image
{
Url = i.Url
};
}
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public ICollection<Image> Images { get; set; }
public Category Category { get; set; }
}
Projection Query
var categoryProjection = Category.Proj().Compile();
var products = _ctx.Products.Select(p => new Product
{
Id = p.Id,
Name = p.Name,
Images = p.Images.AsQueryable().Select(Image.Proj()).ToHashSet(),
Category = categoryProjection.Invoke(p.Category)
});
When I execute the projection then it will work correctly for Product and Images. But for Category the genereted SQL will contain all Columns (Id and CategoryName).

Sequence contains no elements on query

Query:
var result = await this.Context.ShopProducts
.Include(prd => prd.Category)
.ThenInclude(cat => cat.Culture)
.Include(prd => prd.InfoItems)
.SingleOrDefaultAsync(prd => prd.Id.Equals(id) && prd.CategoryId.Equals(culture));
Edit: Updated the entities and query to reflect the new design and added a sql query
Entities:
Product:
[Table("ShopProduct")]
public class Product : ShopBase
{
public bool Active { get; set; } = true;
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
public ICollection<ProductInfo> InfoItems { get; set; } = new HashSet<ProductInfo>();
}
ProductInfo:
[Table("ShopProductInfo")]
public class ProductInfo : ShopBase
{
public int ProductId { get; set; }
public int CultureId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Sum { get; set; }
public ICollection<GraphicItem> GraphicItems { get; set; }
}
What I want is to only select the ProductInfo objects with CultureId that equals the Category CultureId property. When selecting I provide the product Id and Category Id.
I want to replicate something like this sql query:
DECLARE #prdId INT,
#catId INT
SET #prdId = 1
SET #catId = 1
SELECT prd.*,
info.*,
cat.*
FROM ShopProduct prd,
ShopProductInfo info,
ShopCategory cat
WHERE prd.Id = #prdId
AND prd.CategoryId = cat.Id
AND cat.Id = #catId
AND cat.CultureId = info.CultureId
this error mean, linq query return some value otherwise give exception error

Linq how to map collections to object from multiple result sets

How to map collections to object from multiple result sets with Linq
I am trying to map collections to their object but i get wrong result
My business object looks like this
public class ProductForAjax
{
public ProductForAjax()
{
this.DynamicProperties = new List<DynamicProperty>();
this.Categories = new List<Category>();
}
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal ProductPrice { get; set; }
public int ProductQuantity { get; set; }
public IEnumerable<DynamicProperty> DynamicProperties { get; set; }
public IEnumerable<Category> Categories { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
public class DynamicProperty
{
public int PropertyId { get; set; }
public string PropertyName { get; set; }
public string PropertyValue { get; set; }
}
and here is the way i tried to map the collections to the object
var See = db.Database.SqlQuery<GetProduct>("EXEC sp_GetProduct #ProductId", par).ToList();
var grouped = (from c in See
group new
{
c.PropertyId,
c.PropertyName,
c.PropertyValue,
c.SubCategoryId,
c.SubCategoryName
}
by new
{
c.ProductId,
c.ProductName,
c.ProductPrice,
c.ProductQuantity
}).ToList();
ProductForAjax J = grouped.Select(c => new ProductForAjax()
{
ProductId = c.Key.ProductId,
ProductName = c.Key.ProductName,
ProductPrice = c.Key.ProductPrice,
ProductQuantity = c.Key.ProductQuantity,
DynamicProperties = c.Select(x => new DynamicProperty()
{
PropertyId = x.PropertyId,
PropertyName = x.PropertyName,
PropertyValue = x.PropertyValue
}
).ToList(),
Categories = c.Select(y => new Category()
{
CategoryId = y.SubCategoryId,
CategoryName = y.SubCategoryName
}).ToList()
}).FirstOrDefault();
I am actually new to Linq so please don't solve my problem based on my code because i don't know if it's right or not. So Please tell me how such a case solved in real-world

Retrieving data from a second table if it has a record with the Id from another table

I have 2 context tables and I would like to select data from them if the ids are equal.
I would like to do this using LINQ's fluent API.
I want to check if the Id in Movie equals the MovieId in MovieReview, and if so present the ReviewerName from MovieReview, and Name from Movie
The tables are:
public class MovieReview
{
public int Id { get; set; }
[Range(1,10)]
[Required]
public int Rating { get; set; }
[Required]
[StringLength(1024)]
public string Body { get; set; }
[Display(Name="User Name")]
[DisplayFormat(NullDisplayText="anonymous")]
public string ReviewerName { get; set; }
public int MovieId { get; set; }
public class Movie
{
public int Id { get; set; }
public string Name { get; set; }
public string Director { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public virtual ICollection<MovieReview> Reviews { get; set; }
}
Any help is highly appreciated.
So far I made.. not even sure if im close:
var model =
_db.Movies
.Join(_db.Reviews, g => g.Id, u => u.MovieId, (g,u) => new { MovieReview = u, Movie = g})
.Where( (g => g.Movie
select (r => new AdminReviewListViewModels
{
Id = g.Id,
Name = g.Name,
Director = g.Director,
ReleaseDate = g.ReleaseDate,
Genre = g.Genre,
CountOfReviews = g.Reviews.Count(),
UserName = u.ReviewerName
});
If you just need an anonymous enumerable that contains MovieName and ReviewerName properties, this should work.
using (var _db = new YourDbContext())
{
var movies = _db.Movies;
var movieReviews = _db.MovieReviews;
var results = movies.Join(movieReviews,
m => m.Id,
mr => mr.MovieId,
(m, mr) => new { MovieName = m.Name, ReviewerName = mr.ReviewerName }).ToList();
}
You can use:
context.Set<MovieReview>().Select(c=>new{c.ReviewerName, c.Movie.Name})

EF4.1 - Attribute Evaluating to null at runtime

I'm using EF4.1 code first to create a simple database app with SQL CE 4 backend. I have a Product class and a CallItem class defined as so:
class CallItem
{
public int id { get; set; }
public float discount { get; set; }
public virtual Product Product { get; set; }
}
class Product
{
public int id { get; set; }
public decimal BaseCost { get; set; }
public int UnitSize { get; set; }
public bool isWasteOil { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Ingredients { get; set; }
}
edit - When I am creating a collection of CallItems using a LINQ query, I cannot access the attributes of the Product attached to each CallItem, eg
var callItems = from ci in context.CallItems select ci;
foreach(CallItem callItem in callItems)
{
RunSheet nrs = new RunSheet();
nrs.prodCode = callitem.Product.Code;
}
Interrogating the database shows that Productid in CallItems is being populated. However, the following line generates a NullReferenceException during run time:
nrs.prodCode = callitem.Product.Code;
Because callitem.Product is evaluating to null. Is this something to do with lazy loading and if so how can I resolve the issue?
RunSheet is another class, nrs is an instance whose attribute 'prodCode' I want to populate with the CallItem's Product's code.
Thanks!
From that code what you've showed it should work. Have you tried explicit loading?
var callItems = from ci in context.CallItems.Include(c => c.Product) select ci;
foreach(CallItem callItem in callItems)
{
RunSheet nrs = new RunSheet();
nrs.prodCode = callitem.Product.Code;
}
public class CallItem
{
public int Id { get; set; }
public float Discount { get; set; }
public virtual Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
public decimal BaseCost { get; set; }
public int UnitSize { get; set; }
public bool IsWasteOil { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Ingredients { get; set; }
}
using (var context = new StackOverFlowContext())
{
var p = new Product
{
Id = 1,
BaseCost = 200,
Code = "Hola",
Description = "Soe description",
Ingredients = "Some ingredients",
IsWasteOil = true,
Name = "My Product",
UnitSize = 10
};
var item = new CallItem
{
Id = 101,
Discount = 10,
Product = p
};
context.CallItems.Add(item);
context.SaveChanges();
var result = from temp in context.CallItems
select temp;
Console.WriteLine("CallItem Id"+result.First().Id);
Console.WriteLine("ProductId"+result.First().Product.Id);
}
I wrote the above code with the following output
CallItemId 1
ProductId 1
The sql Profiler showed this
SELECT TOP (1)
[c].[Id] AS [Id],
[c].[Discount] AS [Discount],
[c].[Product_Id] AS [Product_Id]
FROM [dbo].[CallItems] AS [c]
It was too long for a comment ,so i put it here .

Categories

Resources