How Can use a native sqlquery (session.CreateSqlQuery) as filtering subquery in another QueryOver:
// Get ids
var idsq = _session.CreateSQLQuery(
"select Id from [dbo].[SomeFunction](:parameter)")
.AddEntity(typeof(long)).
SetParameter("parameter", folderId);
// get entities by filtering where in (subquery)
MyEntity entityAlias = null;
var listOfEntities = await _session.QueryOver(() => entityAlias).
Where(x=>x.Id).IsIn(idsq).
OrderBy(x => x.Name).Asc.
ListAsync(cancelToken).ConfigureAwait(false);
You can't easily mix various styles of NHibernate... What you can do:
var crit = new SQLCriterion(SqlString.Parse("{alias}.Id IN (select Id from [dbo].[SomeFunction](?))"),
new object[] { folderId },
new IType[] { NHibernateUtil.Int64 });
and then:
var listOfEntities = await _session.QueryOver(() => entityAlias)
.Where(crit)
.OrderBy(x => x.Name).Asc
Note how I changed the text query adding {alias}.Id IN (...)
Related
I have the below method that aims to filter records from a table. But sometimes, the user might only select one filter or two. I want to add where conditions only for parameters that the user sends. At the moment, it filters with all conditions. One possibility I know is to use some conditions to concatenate the string if true but I do not think this is the best way.
Any better way of doing this?
// Retrieve hotels by filter
app.get('/filter', (request, response) => {
var name = request.query.name;
var country = request.query.country;
var freeWifi = request.query.freeWifi;
var freeParking = request.query.freeParking;
var restaurant = request.query.restaurant;
var pool = request.query.pool;
var gym = request.query.gym;
var airconditioning = request.query.airconditioning;
let query = `select * from hotels h inner join hotelFilters hf on h.id = hf.hotelId where h.title like "%${isNullOrUndefined(name) ? '' : name}%"
and hf.freeWifi = ${freeWifi} and hf.freeParking = ${freeParking} and hf.restaurant = ${restaurant} and hf.outdoorPool = ${pool}
and hf.airConditioning = ${airconditioning}
and hf.gym = ${gym}`;
connection.query(query, (error, result) => {
if (error) {
console.log(error, 'Error occurred with hotels/filter API...');
}
if (result.length > 0) {
response.send({
result
})
}
})
});
I am creating a query with Criteria like this:
DetachedCriteria auftragCriteria = DetachedCriteria.For<Auftrag>("a");
I join multiple tables with:
DetachedCriteria positionJoin = auftragCriteria.CreateCriteria("a.Positionen", "p", JoinType.LeftOuterJoin);
And I use a projection to fill in my object SubTypeAuftrag
ProjectionList projectionListSubTypeAuftrag = Projections.ProjectionList();
Now I need to recreate the following sql code:
cast(sum(p.length * p.width / 1000) as decimal)
I tried the following:
projectionListSubTypeAuftrag.Add(Projections.Sum<Position>(p => p.length * p.width / 1000), "M1");
This leads to an error:
System.InvalidOperationException: 'variable 'p' of type 'xxx.Base.Position' referenced from scope '', but it is not defined'
I also tried:
projectionListSubTypeAuftrag.Add(
Projections.Cast(
NHibernateUtil.Decimal,
Projections.SqlProjection("p.length * p.width/ 1000 AS result", new[] { "result" }, new IType[] { NHibernateUtil.Double })
),
"M1"
);
How can I tell nHibernate where to find the length/width column?
Maybee this will point you in the right direction.
var sqlMultiply = new VarArgsSQLFunction("(", "*", ")");
var sqlDivide = new VarArgsSQLFunction("(", "/", ")");
var multiplyLengthWidthProj = Projections.SqlFunction(sqlMultiply, NHibernateUtil.Decimal, Projections.Property(() => alias.Length), Projections.Property(() => alias.Width));
var sumProjection = Projections.ProjectionList().Add(Projections.Sum(Projections.SqlFunction(sqlDivide, NHibernateUtil.Decimal, multiplyLengthWidthProj, Projections.Constant(1000))));
I'm attempting to translate some T-SQL to an Entity Framework Core lambda expression. It involves an inner join and a left joing with a where clause.
Here is the working SQL query:
SELECT
AspNetUsers.*, Exclusions.*
FROM
AspNetUsers
JOIN Exclusions ON
AspNetUsers.FirstName = Exclusions.FirstName
AND AspNetUsers.LastName = Exclusions.LastName
LEFT JOIN ExclusionsMatches ON
ExclusionsMatches.RowHash = Exclusions.RowHash
WHERE
ExclusionsMatches.MatchIgnoredByUserId IS NULL
Which I have thus far translated into LINQ lambda as such:
var result = _db.Users
.Join(_db.Exclusions, usr => new { usr.FirstName, usr.LastName }, Exc => new { Exc.FirstName, Exc.LastName }, (usr, Exc) => new { usr, Exc })
.GroupJoin(_db.ExclusionsMatches, i => i.Exc.RowHash, x => x.RowHash, (i, ExcMatch) => new { User = i.usr, Exc = i.Exc, ExcMatch = ExcMatch })
.SelectMany(temp => temp.ExcMatch.DefaultIfEmpty(), (temp, p) => new { User = temp.User, Exc = temp.Exc, ExcMatch = temp.ExcMatch})
This seems to give me the desired query output, but I can't seem to figure out how to get the WHERE ExclusionsMatches.MatchIgnoredByUserId IS NULL clause translated.
Any thoughts on how the WHERE might be achieved? I'm also open to changing from lambda expression to linq query expression.
Thanks!
I believe using LINQ is more readable so I can provide an answer using LINQ as below.
from user in _db.Users
join excl in _db.Exclusions on new { usr.FirstName , usr.LastName} equals {excl.FirstName , excl.LastName}
join exclMtch in _db.ExclusionsMatches on excl.RowHash equals exclMtch.RowHash into grp
from itm in grp.DefaultIfEmpty()
where itm.MatchIgnoredByUserId == null
select new {
user,
excl
}
Otherwise, if you insist on using Lambda, first you have to select the field in your final selects and then add the needed where in the end of query.
var result = _db.Users
.Join(_db.Exclusions, usr => new { usr.FirstName, usr.LastName }, Exc => new { Exc.FirstName, Exc.LastName }, (usr, Exc) => new { usr, Exc })
.GroupJoin(_db.ExclusionsMatches, i => i.Exc.RowHash, x => x.RowHash, (i, ExcMatch) => new { User = i.usr, Exc = i.Exc, ExcMatch = ExcMatch MatchIgnoredByUserId = i.MatchIgnoredByUserId })
.SelectMany(temp => temp.ExcMatch.DefaultIfEmpty(), (temp, p) => new { User = temp.User, Exc = temp.Exc, ExcMatch = temp.ExcMatch, MatchIgnoredByUserId= temp.MatchIgnoredByUserId })
.Where(q => q.MatchIgnoredByUserId == null )
Do not forget to track your query in SQL Profiler :)
As shown in the following unit test I expect stats.TotalResults to be 2 but is 3. Why is that?
[Test]
public void RavenQueryStatisticsTotalResultsTest1()
{
using (var db = _documentStore.OpenSession())
{
db.Store(new Club { Name = "Foo1", Type = "Amateur" }); // --> Matches all conditions
db.Store(new Club { Name = "Foo2", Type = "Professional" });
db.Store(new Club { Name = "Foo3", Type = "Amateur" }); // --> Matches all conditions
db.Store(new Club { Name = "Boo1", Type = "Amateur" });
db.Store(new Club { Name = "Boo2", Type = "Professional" });
db.SaveChanges();
}
WaitForIndexing(_documentStore);
using (var db = _documentStore.OpenSession())
{
RavenQueryStatistics stats;
var query = db.Query<Club>()
.Statistics(out stats)
.Where(club => club.Type == "Amateur")
.Intersect()
.Search(club => club.Name, "Foo*", escapeQueryOptions: EscapeQueryOptions.AllowPostfixWildcard);
var clubs = query.ToList();
Assert.AreEqual(2, clubs.Count);
Assert.AreEqual(2, stats.TotalResults); // I expect 2 but was 3! Why is that?
}
}
You need Intersect when using multiple where clauses. To combine Where and Search, you have to pass SearchOptions.And to Search:
using (var db = _documentStore.OpenSession()) {
RavenQueryStatistics stats;
var query = db.Query<Club>()
.Customize(_ => _.WaitForNonStaleResultsAsOfLastWrite())
.Statistics(out stats)
.Where(club => club.Type == "Amateur")
.Search(
club => club.Name,
"Foo*",
escapeQueryOptions: EscapeQueryOptions.AllowPostfixWildcard,
options:SearchOptions.And);
var clubs = query.ToList();
Assert.AreEqual(2, clubs.Count);
Assert.AreEqual(2, stats.TotalResults);
}
My SQL query:
select [CompanyId]
from dbo.Bussiness_Company
where [BussinessId] in (11,12,13)
group by [CompanyId]
having COUNT(distinct [BussinessId])=3
Explain:
I have a table Bussiness_Company table :
Bussiness_Company
Id*
BussinessId
CompanyId
My data:
Id---------BussinessId------------CompanyId
1----------10---------------------100
2----------11---------------------100
3----------12---------------------100
Resaul query
CompanyId
100
Thank for any hepl!
Sloved:
This is my code:
DetachedCriteria detachedCriteria = DetachedCriteria.For<BussinessCompany>();
detachedCriteria.SetProjection(Projections.Property("Company"));
detachedCriteria.SetProjection(Projections.GroupProperty("Company"));
Disjunction disjunction = Restrictions.Disjunction();
foreach (Bussiness bussiness in list)
{
disjunction.Add(Restrictions.Eq("Bussiness", bussiness ));
} detachedCriteria.Add(disjunction).Add(Restrictions.Eq(Projections.CountDistinct<BussinessCompany>(m => m.Bussiness), list.Count));
IList<Sonomi.Core.BusinessObjects.Bussiness> bussiness =
bussinessUnitManager.CreateCriteria().Add(Subqueries.PropertyIn("Id", detachedCriteria)).List
<Sonomi.Core.BusinessObjects.BussinessUnit>();
dgrCer.DataSource = bussiness;
dgrCer.DataBind();
You can try a such QueryOver code:
var bussinessIdCount = 3;
var bussinessIds = new[] { 11, 12, 13 };
Bussiness_Company bussinessCompany = null;
session.QueryOver(() => bussinessCompany)
.WhereRestrictionOn(() => bussinessCompany.BussinessId).IsIn(bussinessIds)
.Select(Projections.Group(Projections.Property(() => bussinessCompany.CompanyId)))
.Where(Restrictions.Gt(Projections.CountDistinct(() => bussinessCompany.BussinessId), bussinessIdCount));