Is it possible to write an linq select inside order by something like :
ReservationDTO obj = new ReservationDTO();
obj.bookroomview = obj.bookroomview.GroupBy(a => a.RoomFloor)
.Select(a => obj.bookroomview
.Select(x => new { Amount = a.Select(b => b.ReservationRoomID).Count(), Name = a.Key })
.OrderBy(x => x.Amount)
).ToList().AsQueryable();
My aim is to select all obj.roombookview items but sort them according to Count calculation. If it is possible how can i write it?
My view class :
public partial class Book_Room_View
{
public Nullable<int> ReservationID { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<System.DateTime> EndDate { get; set; }
public Nullable<int> ReservationRoomID { get; set; }
public string RoomName { get; set; }
}
if you were to order the groups by reservations, I guess this is the proper way doing it, you don't need to count specific attribute as I guess you are trying, just order by the count of the value list.
obj.bookroomview.GroupBy(a => a.RoomFloor)
.OrderBy(gr => gr.Count())
.Select(gr => new { Amount = gr.Count(), Name = gr.Key })
.AsQueryable();
Related
I have the following structure:
public class Order
{
public string Id { get; set; }
public string CustomerId { get; set; }
public decimal Amount { get; set; }
public DateTimeOffset CreatedDate { get; set; }
}
public class Customer
{
public string Id { get; set; }
public string Name { get; set; }
}
I want to export all customers (RavenDB Stream) with order turnover and last ordered date.
I do already have an index (Customers_ByTurnover) which outputs this data (map=Orders, reduce by CustomerId). Although this does only list customers which have already ordered something.
I need an index for all Customers and load these details into each row.
Here is the code I want to write (the Query method is pseudo and doesn't really exist):
public class Customers_ByOrders : AbstractIndexCreationTask<Customer, Customers_ByOrders.Result>
{
public class Result
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Turnover { get; set; }
public DateTimeOffset? LastOrderedDate { get; set; }
}
public Customers_ByOrders()
{
Map = items => items.Select(item => new Result()
{
Id = item.Id,
Name = item.Name,
Turnover = Query<Order>().Where(x => x.CustomerId == item.Id).Sum(x => x.Amount),
LastOrderedDate = Query<Order>().Where(x => x.CustomerId == item.Id).Select(x => x.CreatedDate).OrderByDescending(x => x).FirstOrDefault()
});
}
}
How can I solve this issue?
You cannot create a query inside an index, to get the desired info you will have to create a map-reduce index on the Orders collection, group by on CustomerId and in the reduce function apply Sum() on Amount field and order the LastOrderedDate. To get the Name name field you will have to use LoadDocument extension.
public class Customers_ByOrders : AbstractIndexCreationTask<Orders, Customers_ByOrders.Result>
{
public class Result
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Turnover { get; set; }
public DateTimeOffset? LastOrderedDate { get; set; }
}
public Customers_ByOrders()
{
Map = orders => from o in orders
select new Result
{
Id = o.CustomerId,
Turnover = o.Amount,
LastOrderedDate = o.CreatedDate
};
Reduce = results => from result in results
group result by result.Id
into g
select new Result
{
Id = g.Key,
Turnover = g.Sum(x => x.Turnover),
LastOrderedDate = g.OrderByDescending(x => x.LastOrderedDate).Select(x => x.LastOrderedDate).FirstOrDefault()
};
}
}
I have two classes :
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Child> Childrens { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
}
Now through Nhibernate QueryOver I want to get list of all Parent with no of Count of children in single query.
Expected output is ?:
ParentId Name ChildrenCount
1 ABC 10
2 CDE 5
can anyone help me .
Using this DTO for projection:
public class ParentDto
{
public int Id { get; set; }
public string Name { get; set; }
public int ChildrenCount { get; set; }
}
Use this query:
Child childAlias = null;
ParentDto dto = null;
var dtoParents = Session.QueryOver<Parent>()
.JoinAlias(x => x.Childrens, () => childAlias)
.SelectList(list => list
.SelectGroup(x => x.Id).WithAlias(() => dto.Id)
.SelectGroup(x => x.Name).WithAlias(() => dto.Name)
.SelectCount(() => childAlias.Id).WithAlias(() => dto.ChildrenCount))
.TransformUsing(Transformers.AliasToBean<ParentDto>())
.List<ParentDto>();
You can read more about QueryOver projections using DTOs here.
I have a SQL statement below that needs to convert it to NHibrnate QueryOver. I have searched the web but can't find a concrete solution. Anyone can help me on this?
SELECT
TABEL1.Id,
CASE WHEN EXISTS (SELECT Id FROM TABLE2 WHERE TABLE2.ID = TABLE1.ID)
THEN 'TRUE'
ELSE 'FALSE'
END AS NewFiled
FROM TABLE1
--Here is the real POCO
public class UserRole
{
[Required]
public virtual User User { get; set; }
[Required]
public virtual Role Role { get; set; }
}
public class UserTenant
{
[Required]
public virtual Tenant Tenant { get; set; }
[Required]
public virtual User User { get; set; }
}
public class Role
{
public int Id {get;set}
[StringLength(255), Required]
public virtual string RoleLabel { get; set; }
[StringLength(4000), Required]
public virtual string RoleDescription { get; set; }
}
public class User
{
public int Id {get;set}
[StringLength(255), Required]
public virtual string Firstname { get; set; }
[StringLength(255), Required]
public virtual string Lastname { get; set; }
}
public class Tenant
{
public int Id {get;set}
[StringLength(255), Required]
public virtual string Name { get; set; }
[StringLength(4000), Required]
public virtual string Description { get; set; }
}
public class AssignRoleUsersModel
{
public virtual int UserId { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual bool IsAssigned { get; set; }
}
--This is the method to get the users assigned or not for that particular role.
public RoleUsers GetRoleUsers(int Id)
{
UserRole userRolesAlias = null;
UserTenant userTenantsAlias = null;
-- This query will get the role depending the Id that have passed. Take note that I don't want to use this query that is why I am converting it to queryOver.
var role = (from r in RoleRepository.Queryable()
where r.Id == Id
select r).FirstOrDefault();
--This query will get all the users having the role result above.Take note that I don't want to use this query that is why I am converting it to queryOver.
var assignedUsers = UserRoleRepository.Queryable().Where(x => x.Role.Id == role.Id).Select(a => a.User.Id).ToArray();
--This is the condition to know if the user was assigned to the role
var projection = Projections.Conditional(Restrictions.Where(() => userRolesAlias.User.Id.IsIn(assignedUsers))
, Projections.Constant(true)
, Projections.Constant(false)
);
var users =
new List<AssignRoleUsersModel>(UnitOfWorkLocalData.CurrentUnitOfWork.Session.QueryOver(() => userTenantsAlias)
.Select(x => x.User.Id)
.Select(x => x.User.LastName)
.Select(x => x.User.FirstName)
.Select(x => x.User.UserName)
.Select(projection)
.TransformUsing(Transformers.AliasToBean<AssignRoleUsersModel>())
.List<AssignRoleUsersModel>());
}
EXTENDED based on the extended question, the way how to do CASE WHEN:
// the ID of searched role, coming as parameter id
int searchedRolId = ...
UserRole userRolesAlias = null;
// this is the SUBQUERY we need, the inner select
var subquery = QueryOver
.Of<UserRole>(() => userRolesAlias)
.Where(() => userRolesAlias.Role.Id == searchedRolId)
.Select(x => userRolesAlias.User.Id);
// here we use NHibernate built in Subqueries tools
var projection = Projections.Conditional(
Subqueries.Exists(subquery.DetachedCriteria) // this is the SUB-SELECT
, Projections.Constant(true)
, Projections.Constant(false)
);
ORIGINAL - This could look like this:
var projection = Projections.Conditional(
NHibernate.Criterion.Expression
.Sql("EXISTS (SELECT Id FROM TABLE2 WHERE TABLE2.ID = {alieas}.ID)")
, Projections.Constant(true)
, Projections.Constant(false)
);
var query = session.QueryOver<Table1>();
ResultDto result = null;
var list = query.SelectList(l => l
.Select(x => x.ID).WithAlias(() => result.ID)
.Select(projection).WithAlias(() => result.DoesExist)
)
.TransformUsing(Transformers.AliasToBean<ResultDto>())
.List<ResultDto>();
The list here contains the set of ResultDtos, with ID and decision if the subtabel TABLE2 record exists. The {alias} will be replaced by NHibernate with the alias of the outert table...
Where this is our DTO for projections:
public class ResultDto
{
public virtual int ID { get; set; }
public virtual bool DoesExist { get; set; }
}
Either I'm having a mental block, or its not that straightforward.
I have 2 classes, something like that:
public class House
{
public string Id { get; set; }
public string City { get; set; }
public string HouseNumber { get; set; }
}
public class Person
{
public string Id { get; set; }
public string HouseId { get; set; }
public string Name { get; set; }
}
Now I want a list of all people living in a given city, in a flattened model ({City, HouseNumber, PersonName}).
I can't figure out a way on how to map that.. If I had a City in a Person class that would be easy, but I don't, and it doesn't make sense there, imo.
Help ?
Edit:
I came up with this index, which actually works with in-memory list, but Raven returns nothing :(
public class PeopleLocations : AbstractMultiMapIndexCreationTask<PeopleLocations.EntryLocation>
{
public class PeopleLocation
{
public string PersonId { get; set; }
public string HouseId { get; set; }
public string City { get; set; }
}
public PeopleLocations()
{
this.AddMap<House>(venues => venues.Select(x => new
{
x.City,
HouseId = x.Id,
PersonId = (string)null
}));
this.AddMap<Person>(people => people.Select(x => new
{
City = (string)null,
HouseId = x.HouseId,
PersonId = x.Id
}));
this.Reduce = results => results.GroupBy(x => x.HouseId)
.Select(x => new
{
HouseId = x.Key,
People = x.Select(e => e.PersonId),
City = x.FirstOrDefault(y => y.City != null).City,
})
.SelectMany(x =>
x.People.Select(person => new PeopleLocation
{
PersonId = person,
HouseId = x.HouseId,
City = x.City,
})
)
.Select(x => new { PersonId = x.PersonId, x.City, x.HouseId });
}
}
You can do this with a MultiMap Index - but there's a great new feature in RavenDB 2.0 called Indexing Related Documents that is much easier.
Map = people => from person in people
let house = LoadDocument<House>(person.HouseId)
select new
{
house.City,
house.HouseNumber,
PersonName = person.Name,
}
I'm trying to use the TransformResults feature, and I can't get it to work. I'm not totally sure I understand this feature, perhaps there is another way to solve this problem. What I want is just the Id from the Order and the email addesses from the Customer and the Entrepreneur. I am happy for all tips that can take me in the right direction. Here is my code.
Document
public class OrderDocument
public string Id {get; set }
public EntrepreneurInfo EntrepreneurInfo { get; set; }
public CustomerInfo CustomerInfo { get; set; }
public OrderStatus CurrentOrderStatus { get; set; }
}
Info classes
public class EntrepreneurInfo
{
public string EntrepreneurDocumentId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
public class CustomerInfo
{
public string CustomerDocumentId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
The info classes are just subsets of a Customer and Entrepreneur documents respectively.
The Customer and Entrepreneur documents inherits from a base class ( AbstractOrganizationDocument) that has the EmailAddress property.
My Index
public class OrdersApprovedBroadcastingData :
AbstractIndexCreationTask<OrderDocument, OrdersApprovedBroadcastingData.ReduceResult>
{
public OrdersApprovedBroadcastingData()
{
this.Map = docs => from d in docs
where d.CurrentOrderStatus == OrderStatus.Approved
select new
{
Id = d.Id,
CustomerId = d.CustomerInfo.CustomerDocumentId,
EntrepreneurId = d.EntrepreneurInfo.EntrepreneurDocumentId
};
this.TransformResults = (db, orders) => from o in orders
let customer = db.Load<CustomerDocument>(o.CustomerId)
let entrepreneur = db.Load<EntrepreneurDocument>(o.EntrepreneurId)
select
new
{
o.Id,
o.CustomerId,
CustomerEmail = customer.EmailAddress,
o.EntrepreneurId,
EntrepreneurEmail = entrepreneur.EmailAddress
};
}
public class ReduceResult
{
public string Id { get; set; }
public string CustomerId { get; set; }
public string CustomerEmail { get; set; }
public string EntrepreneurId { get; set; }
public string EntrepreneurEmail { get; set; }
}
}
If I look at the result of this Index in Raven Studio I get null values for all fields except the Id. And finally here is my query.
Query
var items =
this.documentSession.Query<OrdersApprovedBroadcastingData.ReduceResult, OrdersApprovedBroadcastingData>()
.Select(x => new OrdersToBroadcastListItem
{
Id = x.Id,
CustomerEmailAddress = x.CustomerEmail,
EntrepreneurEmailAddress = x.EntrepreneurEmail
}).ToList();
Change your index to:
public class OrdersApprovedBroadcastingData : AbstractIndexCreationTask<OrderDocument>
{
public OrdersApprovedBroadcastingData()
{
Map = docs => from d in docs
where d.CurrentOrderStatus == OrderStatus.Approved
select new
{
};
TransformResults = (db, orders) =>
from o in orders
let customer = db.Load<CustomerDocument>(o.CustomerInfo.CustomerDocumentId)
let entrepreneur = db.Load<EntrepreneurDocument>(o.EntrepreneurInfo.EntrepreneurDocumentId)
select new
{
o.Id,
CustomerEmailAddress = customer.EmailAddress,
EntrepreneurEmailAddress = entrepreneur.EmailAddress
};
}
}
Your result class can simply be the final form of the projection, you don't need the intermediate step:
public class Result
{
public string Id { get; set; }
public string CustomerEmailAddress { get; set; }
public string EntrepreneurEmailAddress { get; set; }
}
You don't have to nest this class in the index if you don't want to. It doesn't matter either way. You can query either with:
var items = session.Query<Result, OrdersApprovedBroadcastingData>();
Or with
var items = session.Query<OrderDocument, OrdersApprovedBroadcastingData>().As<Result>();
Though, with the first way, the convention tends to be to nest the result class, so really it would be
var items = session.Query<OrderDocument.Result, OrdersApprovedBroadcastingData>();
Note in the index map, I am not including any properties at all. None are required for what you asked. However, if you want to add a Where or OrderBy clause to your query, any fields you might want to filter or sort on should be put in there.
One last thing - the convention you're using of OrderDocument, CustomerDocument, EntrepreneurDocument, is a bit strange. The usual convention is just Order, Customer, Entrepreneur. Think of your documents as the persisted form of the entities themselves. The convention you are using will work, it's just not the one usually used.