NHibernate QueryOver with an Or subquery - nhibernate

Ok I'm losing on this one. I have an NHibernate query that looks something like this
var subQuery = QueryOver.Of<Lead>()
.Where(x => x.Client == user.Client)
.And(x => x.LeadType == leadType && x.LeadType != LeadTypeEnum.Self)
.Select(Projections.Distinct(Projections.Id()));
I use this
var query = Session.QueryOver<Lead>()
.WithSubquery.WhereProperty(x => x.Id).In(subQuery);
This produces what I need
Where lead.id in (select Id from .......)
However, I need to add another subquery. Easy to do like above, but I need this to produce the following
Where lead.id in (select id from .....)
or lead.id in (select id from .......)
The problem is I'm always getting the following
Where lead.id in (select id from .....)
and lead.id in (select id from .......)
Could someone point me in the correct direction to get the Or please

I'm an NH newbie myself , but you might want to try created a disjunction and adding the conditions to it, then adding the disjunction to the QueryOver Where call.
var disjunction = new Disjunction();
disjunction.Add(subQuery1);
disjunction.Add(subQuery2);
var query = Session.QueryOver<Lead>()
.Where(disjunction);

Related

Entity Framework problem with reducing projection

I've been working on improving performance for our .NET core API with EF 5.0.11 by reducing the projection of our queries, but I'm currently stuck with the following scenario:
I improved the projection of the queries like this:
var employeeEmailQuery = context.Employee
.Where(e => e.Active == true)
.Select(e => new EmployeeEmailView
{
Name = e.FullName,
Email = e.Email
});
This reduces the select query to just the two columns I need instead of a SELECT * on 80+ columns in the database.
In my database, I also have columns with translated descriptions. It looks like this:
What I would like to do is select the relevant translated description, based on the current culture, so I added the following code:
var culture = CultureInfo.DefaultThreadCurrentUICulture;
var employeeEmailQuery = context.Employee
.Where(e => e.Active == true)
.Select(e => new EmployeeEmailView
{
Name = e.FullName,
Email = e.Email,
this.SetDescription(e, culture);
});
The SetDescription method checks the culture and picks the correct column to set a Description property in the EmployeeEmailView. However, by adding this code, the query is now once again doing a SELECT *, which I don't want.
Does anybody have an idea on how to dynamically include a select column using EF without rewriting everything into raw SQL?
Thanks in advance.
I think the only way is to use an Interceptor to modify the query, or dynamically generate the EF IQueryable with Expressions.

Need help creating a linq select

I need some help creating an LINQ select, i have a table with some columns in it, but only 2 of interest to this problem.
userid, type
Now this table have many thousands entries, and I only want the top, let’s say 50. So far so good, but the hard part is that there a lot of rows in success that should only be counted as 1.
Example
Type UserId
============
Add 1
Add 1
Add 1
Add 2
I would like this to only be counted as 2 in the limit of rows I am taking out, but I would like all the rows to be outputted still.
Is this possible with a single SQL request, or should I find another way to do this?
Edit: I can add columns to the table, with values if this would solve the problem.
Edit2: Sotred procedures are also an solution
Example 2: This should be counted as 3 rows
Type UserId
============
Add 1
Add 1
Add 2
Add 1
Are you stuck on LINQ?
Add a PK identity.
Order by PK.
Use a DataReader and just count the changes.
Then just stop when the changes count is at your max.
If you are not in a .NET environment then same thing with a cursor.
Since LINQ is deferred you might be able to just order in LINQ and then on a ForEach just exit.
I'm not close to a computer right now so I'm not sure is 100% correct syntax wise, but I believe you're looking for something like this:
data.Select(x => new {x.Type, x.UserId})
.GroupBy(x => x.UserId)
.Take(50);
You could do it with Linq, but it may be a LOT slower than a traditional for loop. One way would be:
data.Where((s, i) => i == 0 ||
!(s.Type == data[i-1].Type && s.UserId == data[i-1].UserId))
That would skip any "duplicate" items that have the same Type and UserID as the "previous" item.
However this ONLY works if data has an indexer (an array or something that implements IList). An IEnumerable or IQueryable would not work. Also, it is almost certainly not translatable to SQL so you'd have to pull ALL of the results and filter in-memory.
If you want to do it in SQL I would try either scanning a cursor and filling a temp table if one of the values change or using a common table expression that included a ROW_NUMBER column, then doing a look-back sub-query similar to the Linq method above:
WITH base AS
(
SELECT
Type,
UserId,
ROW_NUMBER() OVER (ORDER BY ??? ) AS RowNum
FROM Table
)
SELECT b1.Type, b1.UserId
FROM base b1
LEFT JOIN base b2 ON b1.RowNum = b2.RowNum - 1
WHERE (b1.Type <> b2.Type OR b1.UserId <> b2.UserId)
ORDER BY b1.RowNum
You can do this with LINQ, but I think it might be easier to go the "for(each) loop" route...
data.Select((x, i) => new { x.Type, x.UserId, i })
.GroupBy(x => x.Type)
.Select(g => new
{
Type = g.Key,
Items = g
.Select((x, j) => new { x.UserId, i = x.i - j })
})
.SelectMany(g => g.Select(x => new { g.Type, x.UserId, x.i }))
.GroupBy(x => new { x.Type, x.i })
.Take(50);
.SelectMany(g => g.Select(x => new { x.Type, x.UserId }));

Expression type 'NhSumExpression' is not supported by this SelectClauseVisitor

I have a query that I can run in LinqPad, but not in NHibernate LINQ. I found a similar bug on NHibernate Jira NHibernate NH-2865, but I think this perhaps a different bug and I'm looking for possible alternatives.
The query that works in LinqPad using default LINQ to SQL is like this:
from ticket in LotteryTickets
group tiket by ticket.ticketType into g
select new
{
TicketType = g.Key,
TotalWinningTickets = g.Count(b => b.WinAmount != 0),
TotalWon = g.Sum(b => b.WinAmount * b.ticketWeight),
TotalTickets = g.Count(),
}
There are various other ways to count the TotalWinningTickets such as TotalWinningTickets = g.Sum(t => t.WinAmount > 0 ? 1 : 0) or g.Sum(t => t.WinAmount == 0 ? 0 : 1)
Now, with NHibernate LINQ I have been unable to get this working without changing my underlying db table. My alternative was to add a table column called HasWon and I set it to 0 for false and 1 for true. This does work, but I'm left feeling there is a better way other than modifying the db table. Perhaps a subselect using a calculated field. My NHibernate LINQ ended up looking like this:
from ticket in session.Query<Ticket>()
group ticket by ticket.TicketType into g
select new ReportRow
{
TicketType = g.Key,
TotalWinningBets = g.Sum(t => t.HasWon),
TotalTickets = g.Count(),
TotalWon = g.Sum(t => t.WinAmount * t.WagerWeight)
};
What I'm effectively trying to do is multiple Select COUNT in my NHibernate query, but based on different criteria. The strangest this is that NHibernate converts all my Count(t => t.???) incorrectly into COUNT(*) in the generated SQL.
LinqPad generates SQL that works this way:
SELECT SUM(
(CASE
WHEN [t1].[WinAmount] > #p3 THEN #p4
ELSE #p5
END)) AS [value]
Hoping there is a better way.

How can I create a Fluent NHibernate query that uses FetchMode.Select

I am simply trying to write a query that will look like this and be eager loaded:
Select * from Users where Id IN (1,2,3)
Select * from Bids where UserId in (1,2,3)
Right now it's causing problems because the join is returning too many results.
Try using multicriteria (or Future as in this example), should issue 2 queries in 1 batch and give you the eager loading:
var bids = Session.QueryOver<Bid>()
.JoinQueryOver(b => b.User)
.WhereRestrictionOn(u => u.Id).IsIn(ids)
.Future<Bid>();
var users = Session.QueryOver<User>()
.WhereRestrictionOn(u => u.Id).IsIn(ids)
.List<User>();
The only problem is it will join Bid -> User, to avoid that you could use HQL:
var bids = Session.CreateQuery("from Bid b where b.User.id in (:userIds)")
.SetParameterList("userIds", ids)
.Future<Bid>();
var users = Session.QueryOver<User>()
.WhereRestrictionOn(u => u.Id).IsIn(ids)
.List<User>();

Simple Linq question: How to select more than one column?

my code is:
List<Benutzer> users = (from a in dc.Benutzer
select a).ToList();
I need this code but I only want to select 3 of the 20 Columns in the "Benutzer"-Table.
What is the syntax for that?
Here's a query expression:
var users = (from a in dc.Benutzer
select new { a.Name, a.Age, a.Occupation }).ToList();
Or in dot notation:
var users = dc.Benutzer.Select(a => new { a.Name, a.Age, a.Occupation })
.ToList();
Note that this returns a list of an anonymous type rather than instances of Benutzer. Personally I prefer this approach over creating a list of partially populated instances, as then anyone dealing with the partial instances needs to check whether they came from to find out what will really be there.
EDIT: If you really want to build instances of Benutzer, and LINQ isn't letting you do so in a query (I'm not sure why) you could always do:
List<Benutzer> users = dc.Benutzer
.Select(a => new { a.Name, a.Age, a.Occupation })
.AsEnumerable() // Forces the rest of the query to execute locally
.Select(x => new Benutzer { Name = x.Name, Age = x.Age,
Occupation = x.Occupation })
.ToList();
i.e. use the anonymous type just as a DTO. Note that the returned Benutzer objects won't be associated with a context though.
List<Benutzer> users = (from a in dc.Benutzer
select new Benutzer{
myCol= a.myCol,
myCol2 = a.myCol2
}).ToList();
I think that's what you want if you want to make the same kind of list. But that assumes that the properties you are setting have public setters.
try:
var list = (from a in dc.Benutzer select new {a.Col1, a.Col2, a.Col3}).ToList();
but now you have list of anonymous object not of Benutzer objects.