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
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).
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
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
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})
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 .