How can i transfer this to LAMBDA? - c#

Hell sir/mam
this is my raw query
SELECT
dbo.Products.AHPPartnerId,
dbo.Products.Name AS Product,
dbo.AHPPartners.Name AS Partner,
Count(dbo.OrderProducts.ProductId) AS totalCount,
dbo.Products.Id AS ProductId
FROM
dbo.AHPPartners
RIGHT JOIN dbo.Products ON dbo.Products.AHPPartnerId = dbo.AHPPartners.Id
RIGHT JOIN dbo.OrderProducts ON dbo.OrderProducts.ProductId = dbo.Products.Id
GROUP BY
dbo.AHPPartners.Id,
dbo.Products.AHPPartnerId,
dbo.Products.Name,
dbo.AHPPartners.Name,
dbo.Products.Id
ORDER BY
totalCount DESC
how could i transfer this to lambda expression i wanna target it here in my DTO?
{
public long ProductId { get; set; }
public long? PartnerId { get; set; }
public string PartnerName { get; set; }
public string ProductName { get; set; }
public double TotalCount { get; set; }
}

Hello I got an answer already.
var topseller = await Context.Entities.Products
.GroupJoin(Context.Entities.AHPPartners,
products => products.AHPPartnerId,
ahp => ahp.Id,
(products, ahp) => ahp.Select(s => new { p = products, a = s }).DefaultIfEmpty(new { p = products, a = (AHPPartner)null })
).SelectMany(g => g)
.Join(Context.Entities.OrderProducts,
firstJoin => firstJoin.p.Id,
orderProducts => orderProducts.ProductId,
(firstJoin, orderProducts) => new { firstJoin.p, firstJoin.a, orderProducts }
)
.Select(s => new {
ProductName = s.p.Name,
ProductId = s.p.Id,
PartnerName = s.a.Name,
PartnerId = s.a.Id
})
.GroupBy(g => new { g.PartnerName, g.ProductName, g.ProductId, g.PartnerId })
.Select(s => new TopSellerProductDTO {
ProductName = s.Key.ProductName,
PartnerName = s.Key.PartnerName,
PartnerId = s.Key.PartnerId,
ProductId = s.Key.ProductId,
TotalCount = s.LongCount()
})
.ToListAsync();

Related

Sort items of list by field of another table LINQ ASP.NET MVC

So, I have my Products table in SSMS with these properties:
public class Product
{
public int Id {get; set;}
public string Title { get; set; }
public decimal Price { get; set; }
}
and my Reports table:
public class Report
{
public int Id { get; set; }
public int ProductId { get; set; }
public ReportType ReportType { get; set; }
}
I want to return a List<Product> to my View that is sorted based on how many reports each Product has, but I can't figure out how to do it with LINQ. Any help/tip would be appreciated.
If you put nav props in this would be:
context.Products.Include(p => p.Reports).OrderBy(p => p.Reports.Count(*));
But as you have no nav props, perhaps something like:
context.Products.OrderBy(p => context.Reports.Count(r => r.ProductId == p.Id));
The query ends up looking like this for the latter:
SELECT *
FROM p
ORDER BY (SELECT COUNT(*) FROM r WHERE p.id = r.id)
and similar but with a left join, for the former
You could also do it on the client side
var dict = context.Reports.GroupBy(r => ProductId, (k,g) => new { ProductId, Count = g.Count() } )
.ToDictionary(at => at.ProductId, at => at.Count);
Then:
//or OrderByDescending if you want most reported products
var ret = context.Products.ToList().OrderBy(p => dict[p.ProductId]);
If you have some limited list of products:
var prods = context.Products.Where(...).ToList();
var prodIds = prods.Select(p => p.ProductId).ToArray();
var dict = context.Reports
.Where(r => prods.Contains(r.ProductId))
.GroupBy(r => ProductId, (k,g) => new { ProductId, Count = g.Count() } )
.ToDictionary(at => at.ProductId, at => at.Count)
var ret = prods.OrderBy(p => dict[p.ProductId]);

Convert SQL to Linq with EF Core

I am using .NET Core 2.2, EF Core, C# and SQL Server 2017.
I am not able to translate the query I need to Linq.
This is the query I need to convert:
SELECT TOP 5
p.Id,
p.Title,
AVG(q.RatingValue) AvgRating
FROM Movies AS p
INNER JOIN Ratings AS q ON p.Id = q.MovieId
GROUP BY p.Id, p.Title
ORDER BY AvgRating DESC, p.Title ASC
The idea of the previous query is to get the Top 5 movies according to the Avg rating, ordering it by the highest average first, and in case of same average order alphabetically.
So far this is my query that makes the join, but then still missing: the group by, average, and ordering:
public class MovieRepository : IMovieRepository
{
private readonly MovieDbContext _moviesDbContext;
public MovieRepository(MovieDbContext moviesDbContext)
{
_moviesDbContext = moviesDbContext;
}
public IEnumerable<Movie> GetTopFive()
{
var result = _moviesDbContext.Movies.OrderByDescending(x => x.Id).Take(5).
Include(x => x.Ratings);
return result;
}
}
And these are the entities:
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
public int YearOfRelease { get; set; }
public string Genre { get; set; }
public int RunningTime { get; set; }
public IList<Rating> Ratings { get; set; }
}
public class Rating
{
public int Id { get; set; }
public int MovieId { get; set; }
public int UserId { get; set; }
public decimal RatingValue { get; set; }
}
I tried to use Linqer tool also to convert my query to Linq, but it was not working.
I will appreciate any help to convert that query to LINQ for the method "GetTopFive".
Thanks
Try this one -
var data = _moviesDbContext.Movies.Include(x => x.Ratings)
.Select(x => new {
Id = x.Id,
Title = x.Title,
Average = (int?)x.Ratings.Average(y => y.RatingValue)
}).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();
Try as follows:
public IEnumerable<Movie> GetTopFive()
{
var result = _moviesDbContext.Ratings.GroupBy(r => r.MovieId).Select(group => new
{
MovieId = group.Key,
MovieTitle = group.Select(g => g.Movie.Title).FirstOrDefault(),
AvgRating = group.Average(g => g.RatingValue)
}).OrderByDescending(s => s.AvgRating).Take(5).ToList();
return result;
}
This will exclude the movies having no ratings.
But if you do as follows (as artista_14's answer):
public IEnumerable<Movie> GetTopFive()
{
var result = _moviesDbContext.Movies.GroupBy(x => new { x.Id, x.Title })
.Select(x => new {
Id = x.Key.Id,
Title = x.Key.Title,
Average = x.Average(y => y.Ratings.Sum(z => z.RatingValue))
}).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();
return result;
}
this will include the movies having no ratings also.
Note: I see your Rating model class does not contain any Movie navigation property. Please add this as follows:
public class Rating
{
public int Id { get; set; }
public int MovieId { get; set; }
public int UserId { get; set; }
public decimal RatingValue { get; set; }
public Movie Movie { get; set; }
}
and finally this is the code working nicely:
var data = _moviesDbContext.Movies.Include(x => x.Ratings)
.Select(x => new MovieRating
{
Id = x.Id,
Title = x.Title,
Average = x.Ratings.Average(y => y.RatingValue)
}).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();
return data;
The problem was creating an anonymous type in the select, so this line resolves the issue: .Select(x => new MovieRating
And this is the complete code for the method and the new class I have created to map the select fields with a concrete type:
public class MovieRepository : IMovieRepository
{
private readonly MovieDbContext _moviesDbContext;
public MovieRepository(MovieDbContext moviesDbContext)
{
_moviesDbContext = moviesDbContext;
}
public IEnumerable<Movie> GetAll()
{
return _moviesDbContext.Movies;
}
public IEnumerable<MovieRating> GetTopFive()
{
var result = _moviesDbContext.Movies.Include(x => x.Ratings)
.Select(x => new MovieRating
{
Id = x.Id,
Title = x.Title,
Average = x.Ratings.Average(y => y.RatingValue)
}).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();
return result;
}
}
public class MovieRating
{
public int Id { get; set; }
public string Title { get; set; }
public decimal Average { get; set; }
}

query linq about 2 lists group by

I have the following query in linq, which takes 2 lists as a data source. The first contains a list of ProductID and its description
public class Venta
{
public string ProductoId { get; set; }
public string clienteRut { get; set; }
}
public class Ventas
{
public List<Venta> lstVentas { get; set; }
}
and the other list has the products sold
public class Productos
{
public List<Producto> lstProductos { get; set; }
}
public class Producto
{
public string id { get; set; }
public string name { get; set; }
}
I need to consult the 5 most sold products, ordered by quantity from the most sold, to the least sold.
So far I have the following linq query, but I do not know how to do it so that I am given the list of the first 5, ordered from highest to lowest based on the quantity (cont)
Venta vta1 = new Venta();
vta1.ProductoId = "1";
vta1.clienteRut = "121370654";
Venta vta2 = new Venta();
vta2.ProductoId = "2";
vta2.clienteRut = "121370654";
Venta vta3 = new Venta();
vta3.ProductoId = "3";
vta3.clienteRut = "121370654";
List<Venta> lstVentasDia = new List<Venta>();
lstVentasDia.Add(vta1);
lstVentasDia.Add(vta2);
lstVentasDia.Add(vta3);
VentasDia vtas = new VentasDia();
vtas.date = "2018-05-01";
vtas.lstVentas = lstVentasDia;
var Lista5Top = from vendidos in vtas.lstVentas
orderby vendidos.ProductoId
group vendidos by vendidos.ProductoId into Grupo
select new { key = Grupo.Key, cont = Grupo.Count() };
I need in addition to that group of result, add the name of the product that is in the list Products, and order it by quantity sold of greater to less only the first 5
Thankful in advance
Gloria
Try following :
Productos productos = new Productos();
var Lista5Top = (from vendidos in vtas.lstVentas
join prod in productos.lstProductos on vendidos.ProductoId equals prod.id
select new { id = vendidos.ProductoId, rut = vendidos.clienteRut, name = prod.name })
.OrderBy(x => x.id)
.GroupBy(x => x.id)
.Select(x => new { id = x.Key, cont = x.Count(), name = x.FirstOrDefault().name })
.OrderByDescending(x => x.cont)
.Take(5).ToList();

Group By using Linq

I need to present a list of Ads grouped by category, including the Ads Count for each category.
Categories are grouped by a Parent Category like Cars that include the Categories Saloon, Cabriolet and Sports.
Models:
public class Ad
{
[Key]
public int Id { get; set; }
public Category Category { get; set; }
}
public class Category
{
public int Id { get; set; }
[ForeignKey("CategoryParent")]
public int? CategoryParent_Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Ad> Ads { get; set; }
}
The result as to be:
Cars - Count: 100 (where 100 is the sum of for example 20 Saloon's Ads, 80 Cabrilet's)
At the moment, I'm only able to present the list of all Categories, and not grouped by Parent Category.
var adIds = {1,2,4,5}
var result =
from c in categoryQuery
let searchCount = c.Ads.Count(a => adIds.Contains(a.Id))
where searchCount > 0
select new CategoryGetAllBySearchDto
{
Id = c.CategoryParent_Id,
Name = c.CategoryParent.Name,
SearchCount = searchCount,
Ids = c.Ads.Where(a => adIds.Contains(a.Id)).Select(a => a.Id)
};
GroupBy in memory:
var adIds = { 1, 2, 4, 5 };
var result = categoryQuery.Where(c => c.Ads.Any(a => adIds.Contains(a.Id)))
.Select(c => new
{
c.CategoryParent_Id,
c.CategoryParent.Name,
Ids = c.Ads.Where(a => adIds.Contains(a.Id)).Select(a => a.Id).AsEnumerable()
})
.ToList()
.GroupBy(c => new {c.CategoryParent_Id, c.Name})
.Select(g => new CategoryGetAllBySearchDto
{
Id = g.Key.CategoryParent_Id,
Name = g.Key.Name,
Ids = g.SelectMany(u => u.Ids).AsEnumerable()
})
.ToList();
i think you need this:
var adIds = { 1, 2, 4, 5 };
var result = from c in categoryQuery
where c.Ads.Any(a => adIds.Contains(a.Id))
group c by new {c.CategoryParent_Id, c.CategoryParent.Name} into g
select new CategoryGetAllBySearchDto
{
Id = g.Key.CategoryParent_Id,
Name = g.Key.Name,
SearchCount = g.SelectMany(u => u.Ads)
.Where(a => adIds.Contains(a.Id))
.Count(),
Ids = g.SelectMany(u => u.Ads)
.Where(a => adIds.Contains(a.Id))
.Select(a => a.Id)
};
you can get out the SearchCount an add the AsEnumerable to Ids to get query just once
public class CategoryGetAllBySearchDto
{
public int? Id { get; set; }
public string Name { get; set; }
public int SearchCount { get { return this.Ids.Count() } }
public IEnumerable<int> Ids { get; set; }
}
and the query :
var adIds = { 1, 2, 4, 5 };
var result = from c in categoryQuery
where c.Ads.Any(a => adIds.Contains(a.Id))
group c by new {c.CategoryParent_Id, c.CategoryParent.Name} into g
select new CategoryGetAllBySearchDto
{
Id = g.Key.CategoryParent_Id,
Name = g.Key.Name,
Ids = g.SelectMany(u => u.Ads)
.Where(a => adIds.Contains(a.Id))
.Select(a => a.Id)
.AsEnumerable()
};

WCF getting entity from WCF service

I have a WCF Service Library and Widnows Form as a client. I have database ADO.NET EF
I want to list all of the products (clothes) with their sizes. (Relation 1 to many).
public partial class ProductsEntity
{
public ProductsEntity()
{
this.Sizes = new HashSet<SizesEntity>();
}
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public virtual ICollection<SizesEntity> Sizes{ get; set; }
}
this is my data contract:
[DataContract]
public class Products
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name{ get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public virtual ICollection<SizesEntity> Sizes{ get; set; }
}
[DataContract]
public class Sizes
{
[DataMember]
public int ID { get; set; }
[DataMember]
public int Name { get; set; }
[DataMember]
public Nullable<int> Quantity { get; set; }
[DataMember]
public int ID_Product { get; set; }
[DataMember]
public virtual ProductsEntity Products { get; set; }
}
i dont have this in data base, but i added Products_with_sizes for my query (Im not sure its a good way of dealing with it)
[DataContract]
public class Products_with_sizes
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public int S { get; set; }
[DataMember]
public int M { get; set; }
[DataMember]
public int L { get; set; }
}
using (var context = new dbMagazynierEntities())
{
var q = (from p in context.Products
where p.Name.Contains(name) && p.Price>= Price_from && p.Price <= Price_to
join r in context.Sizes
on p.ID equals r.Prodcuts.ID
into sizes
select new
{
ID = p.ID,
Name= p.Name,
Price = p.Price,
S = sizes.Where(x => x.Name== 0).Sum(x => x.Quantity) ?? 0,
M = sizes.Where(x => x.Name== 1).Sum(x => x.Quantity) ?? 0,
L = sizes.Where(x => x.Name== 2).Sum(x => x.Quantity) ?? 0,
});
odp = new List<Products_with_sizes>();
foreach (var item in q)
{
odp.Add(new Products_with_sizes{ ID = item.ID, Name= item.Name, Price = item.Price, S = item.S, M = item.M, L = item.L });
}
so know I use this method in my client and i get error
wyn = context.SzukajProduktu(id, name.Text, price_from, price_to);
i get:
Cannot implicitly convert type 'System.Collections.Generic.List<Magazynier2WindowsFormsApplication.ServiceReference1.MyServiceProducts_with_sizes>' to 'System.Collections.Generic.List<Magazynier2ServiceLibrary.MyService.Products_with_sizes>'
By looking at your exception, it seems that you're trying to directly cast a class generated by your service proxy to the DTO you created yourself.
Even though those 2 classes have the same name and properties, they are in fact different (i.e. have no common parent or inteface) and are in a different namespace.
You should write a method that would translate the proxy generated class to your DTO class explicitely, e.g.
List<Magazynier2ServiceLibrary.MyService.Products_with_sizes> TranslateProxyClassToDTO(List<Magazynier2WindowsFormsApplication.ServiceReference1.MyServiceProducts_with_sizes> input)
{
// translate all items and their properties and return the translated list
}
public List<Prodcuts_with_sizes> SzukajProduktu(int id, string name, decimal price_from, decimal price_to)
{
List<Prodcuts_with_sizes> odp;
if (id == -1) //when id is not given
{
using (var context = new dbMagazynierEntities())
{
var q = (from p in context.Products
where p.Name.Contains(name) && p.Price >= price_from && p.Price <= price_to
join r in context.Size
on p.ID equals r.Products.ID
into sizes
select new
{
ID = p.ID,
Name = p.Name,
Price = p.Price,
S = sizes.Where(x => x.Name == 0).Sum(x => x.Quantity) ?? 0,
M = sizes.Where(x => x.Name == 1).Sum(x => x.Quantity) ?? 0,
L = sizes.Where(x => x.Name == 2).Sum(x => x.Quantity) ?? 0,
});
odp = new List<Prodcuts_with_sizes>();
foreach (var item in q)
{
odp.Add(new Prodcuts_with_sizes { ID = item.ID, Name = item.Name, Price = item.Price, S = item.S, M = item.M, L = item.L });
}
//dataGridView1.DataSource = q.ToList();
}
return odp;
}
else //when id is given
{
using (var context = new dbMagazynierEntities())
{
var q = (from p in context.Products
where p.ID == id
join r in context.Sizes
on p.ID equals r.Products.ID
into sizes
select new
{
ID = p.ID,
Name = p.Name,
Price = p.Price,
S = sizes.Where(x => x.Name == 0).Sum(x => x.Quantity) ?? 0,
M = sizes.Where(x => x.Name == 1).Sum(x => x.Quantity) ?? 0,
L = sizes.Where(x => x.Name == 2).Sum(x => x.Quantity) ?? 0,
});
odp = new List<Prodcuts_with_sizes>();
foreach (var item in q)
{
odp.Add(new Prodcuts_with_sizes { ID = item.ID, Name = item.Name, Price = item.Price, S = item.S, M = item.M, L = item.L });
}
}
return odp;
}
}
using (var context = new MyInterfaceClient())
{
wyn = context.SzukajProduktu(id, name.Text, price_from, price_to);
//return wyn;
}
I resolved it by changing
[OperationContract]
List<WCFLIB.MyService.Products_with_sizes> SzukajProduktu(int id, string name, decimal price_form, decimal price_to);
to
[OperationContract]
List<MyService.Products_with_sizes> SzukajProduktu(int id, string name, decimal price_form, decimal price_to);

Categories

Resources