Cannot Index on array of int RavenDB - c#

I'm trying to query on a property of type IEnumerable int to find all documents in the collection that contain an integer value in this property.
I've tried to accomplish this with an index on the property to return a list of id's which satisfy the query. I am projecting the id's in the query however I'm getting a list of id 0's.
Index
public class Merchants_CategoryId : AbstractIndexCreationTask<Merchant>
{
public class Result
{
public int MerchantId { get; set; }
public IEnumerable<int> CategoryIds { get; set; }
}
public Merchants_CategoryId()
{
Map = merchants => merchants.Select(merchant => new
{
CategoryIds = merchant.Header.CategoryIds,
MerchantId = merchant.Header.Id
});
}
}
Query
return await session
.Query<Merchants_CategoryId.Result, Merchants_CategoryId>()
.Where(x => x.CategoryIds.Any(c => c == categoryId))
.Select(x => x.MerchantId)
.ToListAsync();

Index:
public class Merchants_CategoryId : AbstractIndexCreationTask<Merchant>
{
public class Result
{
public int MerchantId { get; set; }
public int CategoryId { get; set; }
}
Map = merchants => from merchant in merchants
from categoryId in merchant.Header.CategoryIds
select new
{
MerchantId = merchant.Header.Id,
CategoryId = categoryId
};
Index(x => x.CategoryId, FieldIndexing.Yes);
Store(x => x.MerchantId, FieldStorage.Yes);
}
Query:
return await session
.Query<Merchants_CategoryId.Result, Merchants_CategoryId>()
.Where(x => x.CategoryId == categoryId)
.Select(x => x.MerchantId)
.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]);

I am trying to get all employee positions (relationship many-to-many)

I'm a beginner. I try to get all the positions of the employee, but only the position of the first employee is returned. Employees and positions relationship is many-to-many. Whatever you do, the result is the same :(
View Model
public class DivisionEmployeeViewModel
{
public DivisionEmployee DivisionEmployees { get; set; }
public Division Division { get; set; }
public IEnumerable<DivisionEmployee> DivisionEmployeeList { get; set; }
public IEnumerable<EmployeePosition> EmployeePositionList { get; set; } // get 1 obj
public IEnumerable<SelectListItem> DivisionEmployeeListDropDown { get; set; }
}
Action Details
[HttpGet]
public async Task<IActionResult> Details(int id)
{
var model = new DivisionEmployeeViewModel
{
DivisionEmployeeList = await _db.DivisionEmployeesModel.Include(x => x.Employee)
.Include(x => x.Division).Where(x => x.Division_Id == id).ToListAsync(),
// Get only 1 obj
EmployeePositionList = await _db.EmployeePositions.Include(x => x.Position)
.Include(x => x.Employee).Where(x => x.Employee_Id == id).ToListAsync(),
//
DivisionEmployees = new DivisionEmployee()
{
Division_Id = id
},
Division = await _db.Divisions.FirstOrDefaultAsync(x => x.Id == id)
};
List<int> tempAssignedList = model.DivisionEmployeeList.Select(x => x.Employee_Id).ToList();
List<int> tempAssignedList2 = model.EmployeePositionList.Select(x => x.Position_Id).ToList(); // ? Get only 1 obj
// Get all items who's Id isn't in tempAuthorsAssignedList and tempCitiesAssignedList
var tempList = await _db.Employees.Where(x => !tempAssignedList.Contains(x.Id)).Where(x => !tempAssignedList2.Contains(x.Id)).ToListAsync();
model.DivisionEmployeeListDropDown = tempList.Select(x => new SelectListItem
{
Text = x.FullName,
Value = x.Id.ToString()
});
return View(model);
}
Project GitHub https://github.com/ValencyJacob/DepartmentManagementApp-Many-to-Many
Your Division_Id and Employee_Id are both id in Details(int id)?And tempAssignedList2 is a list of positionId,why you use .Where(x => !tempAssignedList2.Contains(x.Id)) to compare employeeId with positionId? – Yiyi You

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; }
}

LINQ GroupBy return dictionary with given objects as value

I have an IEnumerable<ValueObj> object with multiple valid ValueObj objects in it. I would like to group those objects by Id and receive Dictionary<Guid, IEnumerable<ValueObj>> where the Key is Id from ValueObj, and Value is just unchanged ValueObj.
public class ValueObj
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
public double Result { get; set; }
}
I've tried to mess with Linq GroupBy but with no success
IEnumerable<ValueObj> persons = ...;
var results = persons.GroupBy(
p => p.Id,
p => p,
(key, g) => new { PersonId = key, Cars = g.ToList() });
Try this:
IEnumerable<ValueObj> col = ...;
var dict = col.GroupBy(x => x.Id).ToDictionary(x => x.Key, x => x.ToList());

NHibernate - filtering out results based on child-property

I have this code fetching all enabled Groups with their children. The problem I have is that the children can also be disabled but I can't get fluent nhibernate to only fetch groups where all childrens are enabled. I assume this is possible but how?
public class Group {
public bool IsDisabled { get; set; }
public string Description { get; set; }
public ICollection<ChildType> Children { get; protected set; }
}
public class ChildType {
public bool IsDisabled { get; set; }
public string Description { get; set; }
}
public IList<Group> Search(string searchString) {
IQueryOver<Group> query = Session.QueryOver<Group>()
.WhereRestrictionOn(x => x.Description).IsInsensitiveLike(searchString, MatchMode.Start)
.Where(x => !x.IsDisabled)
.OrderBy(x => x.Description).Asc
.Fetch(group => group.Children).Eager;
return query
.Cacheable()
.List();
}
Edit: There is a N:M-relation between children and groups.
The following is the solution I used:
public class Group {
public long Id { get; set; }
public bool IsDisabled { get; set; }
public string Description { get; set; }
public ICollection<ChildType> Children { get; protected set; }
}
public class ChildType {
public long Id { get; set; }
public bool IsDisabled { get; set; }
public string Description { get; set; }
public ICollection<Group> Groups { get; protected set; }
}
public IList<Group> Search(string searchString) {
ChildType child = null;
Group group = null;
Group joinedGroup = null;
var notDisabled = Session.QueryOver.Of<ExaminationType>()
.Where(x => x.IsDisabled)
.JoinAlias(x => x.Groups, () => joinedGroup )
.Where(x => joinedGroup == group)
.Select(x => x.Id);
IQueryOver<Group> query = Session.QueryOver<Group>()
.WhereRestrictionOn(x => x.Description).IsInsensitiveLike(searchString, MatchMode.Start)
.JoinAlias(x => x.ExaminationTypes, () => child)
.WithSubquery.WhereNotExists(notDisabled)
.OrderBy(x => x.Description).Asc;
return query
.Cacheable()
.List();
}
You need to use a subquery in order to achieve what you want. In order to do this though you're going to need to add a Group reference to the ChildType entity.
Group group = null;
var childCrit = QueryOver.Of<ChildType>()
.Where(c => c.Group == group).And(c => c.IsDisabled)
.Select(c => c.Id);
var query = Session.QueryOver(() => group)
.WhereRestrictionOn(x => x.Description).IsInsensitiveLike(searchString, MatchMode.Start)
.Where(x => !x.IsDisabled)
.WithSubquery.WhereNotExists(childCrit)
.OrderBy(x => x.Description).Asc
.Fetch(group => group.Children).Eager;
This will get all groups that aren't disabled and have no disabled children.
public IList<Group> Search(string searchString) {
Children children = null;
IQueryOver<Group> query = Session.QueryOver<Group>()
.WhereRestrictionOn(x => x.Description).IsInsensitiveLike(searchString, MatchMode.Start)
.Where(x => !x.IsDisabled)
.JoinAlias(x => x.Children, () => children)
.Where(x => !x.IsDisabled)
.OrderBy(x => x.Description).Asc;
return query
.Cacheable()
.List();
}
That should do what you want to do.
Joining an alias will also fetch it for you.
http://www.philliphaydon.com/2011/04/nhibernate-querying-relationships-are-depth/

Categories

Resources