I am using blow code for join in nhibernate, which is working fine. But i don't wants to use .List on both queries before join, i wants to use .List after join. I don't know nhibernate too much.. please provide me help that what i should make changes in below funciton to first join the data and then apply .List over it.
public IEnumerable<PGrp> GetSol()
{
_pGrpR = null;
_pGrp = null;
QueryOver<Phy, Phy> activePhyQuery = GetDataQuery();
var phyGrpR = _session.QueryOver(() => _pGrpR)
.Where(
Subqueries.WhereProperty<PGrpR>(p => _pGrpR.PhyId).In(
activePhyQuery))
.List<PGrpR>();
IList<PGrp> pGrps = _session.QueryOver(() => _pGrp)
.Where(x => !x.AC)
.List<PGrp>();
var newPGrps = pGrps
.Join(
pGrpR,
p => p.Id,
x => x.PGrpId,
(p, x) => p
).Distinct().OrderBy(x => x.Name);
return newPGrps;
}
Thanks
PGrpR pGrpR = null;
IList<PGrp> pGrps = _session.QueryOver(() => _pGrp)
.Where(x => !x.AC)
.JoinAlias(pgrps => pgrps.pGrpR, () => pGrpR) // Set real property name
.OrderBy(() => pGrpR.Name).Asc
.Select(Projections.Distinct(Projections.Property(() => pGrpR."PropertyForDistinct")))
.TransformUsing(Transformers.DistinctRootEntity)
.List<PGrp>();
Related
I'm trying to get Ingredients through junction table for my Recipes.
_context.RecipeIngredients
.Include(rI => rI.Recipe)
.ThenInclude(r => r.RecipeIngredients)
.Where(rI => ingredients.Contains(rI.IngredientId))
.GroupBy(rI => rI.Recipe)
.Select(g => new
{
Recipe = g.Key,
MatchingIngredients = (double)g.Count() / (double)g.Key.RecipeIngredients.Count(),
g.Key.ComplexityTag,
g.Key.TypeTag,
g.Key.RecipeIngredients,
})
.OrderByDescending(r => r.MatchingIngredients)
.Take(MaxAmountBestRecipes)
.AsEnumerable()
.Select(a => new RecipeDTO()
{
Title = a.Recipe.Title,
Steps = a.Recipe.Steps,
ComplexityTag = a.ComplexityTag?.Complexity,
TypeTag = a.TypeTag?.Type,
IngredientAmount = a.RecipeIngredients?.ToDictionary(rI => rI.Ingredient.Name, rI => rI.Quantity),
})
.ToList();
I discovered it is caused by g.Key.RecipeIngredients, but I can't find any workaround, solution for this problem. I tried eagar loading(as you can see), and lazy loading, both didn't work. I hope there is solution in one query to db in linq. Moreover, will it work like in the above line, after update.:
IngredientAmount = a.RecipeIngredients?.ToDictionary(rI => rI.Ingredient.Name, rI => rI.Quantity)
EDIT
I have divied linq query and here you have after which statement ArgumentNullException is thrown:
var tmp = _context.RecipeIngredients
.Where(rI => ingredients.Contains(rI.IngredientId))
.GroupBy(rI => rI.Recipe)
.Select(g => new
{
Recipe = g.Key,
MatchingIngredients = (double)g.Count() / (double)g.Key.RecipeIngredients.Count(),
g.Key.ComplexityTag,
g.Key.TypeTag,
g.Key.RecipeIngredients
})
.ToList();
Include doesn't work when you change the shape of the query (e.g. when you're querying for RecipeIngredients but are projecting to another type).
The only place I'm thinking a NULL is a problem is the key selector when creating the dictionary. Since Include won't do anything for you, ri.Ingredient will always be NULL. Include the Ingredients in the original projection (and remove the Include since it's useless):
_context.RecipeIngredients
.Where( rI => ingredients.Contains( rI.IngredientId ) )
.GroupBy( rI => rI.Recipe )
.Select( g => new
{
Recipe = g.Key,
MatchingIngredientCount = (double)g.Count() / (double)g.Key.RecipeIngredients.Count(),
g.Key.ComplexityTag,
g.Key.TypeTag,
g.Key.RecipeIngredients,
// this eager-loads the `Ingredient` entities
// EF will automatically wire them up to the `RecipeIngredient` entities
// if tracking is enabled
Ingredients = g.Key.RecipeIngredients.Select( ri => ri.Ingredient ),
} )
.OrderByDescending(r => r.MatchingIngredients)
.Take(MaxAmountBestRecipes)
.ToArray()
.Select( a = new ...
{
...
IngredientAmount = a.RecipeIngredients.ToDictionary(
ri => ri.Ingredient.Name, // ri.Ingredient should now not be NULL
ri => ri.Quantity )
} );
Edit: if you don't need the entire RecipeIngredient or Recipe entities in your results, just project what you need in the orig name with the RecipeIngredients in the first projection:
IngredientNamesAndQuantity = g.Key.RecipeIngredients.Select( ri => new
{
ri.Quantity,
ri.Ingredient.Name,
}
Then use that projection to build your dictionary:
IngredientAmount = a.IngredientNamesAndQuantity.ToDictionary(
at => at.Name,
at => at.Quantity )
I am trying to eager load some properties using Include method as following:
var dbData = dbContext.Locators.Include(x => x.PhysicalObjects.Select(p => p.Parent)).Include(x => x.PhysicalObjects.Select(p =>p.Type.AllowedSubTypes))
.Where(x => x.id==1)).Select(x => new
{
newContainer = x.PhysicalObjects.Where(p => p.Id== newContainerId).FirstOrDefault(),
phyiscalObject = x.PhysicalObjects.Where(p => p.Id == id).FirstOrDefault()
}).FirstOrDefault();
But it returns Parent and Type properties as null(I checked database they are not null).
So how can I eager load those properties?
P.S
I am using Entity Framework V6.1.3
Depending on DevilSuichiro's comment above the query will be like this:
var dbData = dbContext.Locators.Include(x => x.PhysicalObjects.Select(p => p.Parent)).Include(x => x.PhysicalObjects.Select(p =>p.Type.AllowedSubTypes))
.Where(x => x.Id==1)).Take(2).ToList().Select(x => new
{
newContainer = x.PhysicalObjects.Where(p => p.Id== newContainerId).FirstOrDefault(),
phyiscalObject = x.PhysicalObjects.Where(p => p.Id == id).FirstOrDefault()
}).FirstOrDefault();
It worked for me, but I will still be waiting for better answer if any.
I have this query witch is working fine :
List<IGrouping<Country, VisitedCity>> tempQuery = null;
using (var db = new MyDataContext())
{
tempQuery = db.VisitedCities.Include(c => c.PersonWhoVisited).Include(c => c.PersonWhoVisitedNationality).Include(c => c.City)
.GroupBy(c => c.PersonWhoVisitedNationality)
.ToList();
}
var dataInput = tempQuery
.OrderBy(c => c.Key.Name)
.Select(cp => new
{
CountryName = cp.Key.Name,
VisitationsByCity = cp
.GroupBy(x => x.City, x => x.CityId)
.Select(c => new
{
City = c.Key,
NumberOfVisits = c.Count()
})
}).ToList();
But the problem is that it is loading all data to my application (i have now 300 000 rows already on my largest table) and its getting slow day by day of course because its loading all in the ToList() method call.
I have this splitted in two calls because i cannot figure out how to make a single call to the database and return only the dataInput, if i merge both calls into one i get "Object reference not set to an instance of an object." exeption, this is probably because some references are not being included, but i cannot figure out what more tables i include in the query...
also im using entity framework 7 which still doesn't support lazy loading and has some features missing still, but this should be possible right?
In the includes i tried using a select statement
.Include(c => c.LadiesInWaiting.Select(b => b.Princess))
like mentioned on here : http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx
but is not recognized (because its new entity framework 7 ?)
Update :
Ok if i use the .AsEnumerable i can make all in a single query, but still it seems to take for about 6 seconds to load the data in the next call and also loads 250 mb worth of memory at this instance of time ...
var tempQuery = db.VisitedCities.Include(c => c.PersonWhoVisitedNationality).Include(c => c.City)
.GroupBy(c => c.PersonWhoVisitedNationality)
.AsEnumerable()
.OrderBy(c => c.Key.Name)
.Select(cp => new
{
CountryName = cp.Key.Name,
VisitationsByCity = cp
.GroupBy(x => x.City, x => x.CityId)
.Select(c => new
{
City = c.Key,
NumberOfVisits = c.Count()
})
});
var allCities1 = tempQuery
.SelectMany(x => x.VisitationsByCity.Select(c => c.City))
.Distinct().OrderBy(city => city.Name).ToList();
Ok so i managed (of sort :P) to put all in a single query but i still have to call the .ToList() in order for the next data retrievals to work, if someone has a better solution please let me know .
var dataInput = db.VisitedCities
.GroupBy(c => c.PersonWhoVisitedNationalityId)
.Join(db.Countries, s => s.Key, c => c.CountryId, (s, c) => new { s, c })
.OrderBy(c => c.c.Name)
.Select(cp => new
{
Country = cp.c,
VisitationsByCity = cp.s
.GroupBy(x => x.CityId)
.Join(db.Cities, s => s.Key, c => c.CityId, (s, c) => new { s, c })
.Select(c => new
{
City = c.c,
NumberOfVisits = c.s.Count()
})
}).ToList();
How do fetch data from multiple tables with method syntax without using joins, but only .where() methods?
I'm making a select against EF5 db context which maps to this legacy table structure where I have a persons detail table and another table which refers both to itself to create a hierarchy and to the person details table this way:
PersonSet
.Where(p => p.LastName.ToLower()=="surname")
.Join(SubsetSet, p => p.Id, ss => ss.SubsetLink, (p, ss) => new { PersonDetail = p, person = ss })
.Where(m => m.person.Frame=="a" && m.person.Purpose=="1")
.Join(SubsetSet, ss1 => ss1.person.Owner, person => person.SubsetLink, (ss1, ss2) => new { person = ss1, club = ss2 })
.Where(a => a.club.Frame=="b" && a.club.Purpose=="2")
.Join(SubsetSet, ss => ss.club.Owner, ss2 => ss2.SubsetLink, (ss, ss2) => new { club = ss, association = ss2 })
.Where(a => a.association.Frame=="b" && a.association.Purpose=="3")
.Join(SubsetSet, ss => ss.association.Owner, ss3 => ss3.SubsetLink, (ss, ss3) => new { association = ss, district = ss3})
.Where(d => d.district.Frame=="b" && d.district.Purpose=="4" && d.district.SubsetLink=="12345")
.Select(proj => new { proj.association.club.person, proj.association.club, proj.association, proj.district })
.OrderByDescending(a => a.association.club.person.phyperson.FirstName)
.Take(10).Dump();
The above query works at least in LinqPad but, it seems to me that If I could get rid of those joins the statement might look a bit nicer. Now I know, like in the Albahari example below, that this can be done with query syntax. But I couldn't find an example that would illustrate this situation with method syntax. The way I'm trying to approach this might of course be wrong and that's why I can't find suitable examples.
Here I found something similar, but couldn't make it work in LinQPad:
Is multiple .Where() statements in LINQ a performance issue?
Or this one, where the solution is again in query syntax:
Cross Join with Where clause
Or this example by Albahari: (http://www.linqpad.net/WhyLINQBeatsSQL.aspx)
from p in db.Purchases
where p.Customer.Address.State == "WA" || p.Customer == null
where p.PurchaseItems.Sum (pi => pi.SaleAmount) > 1000
select p
Consider this query:
var q = from order in orders
from orderline in order.Lines
where orderline.Count > 10
select order.Discount * orderline.Price;
this more or less corresponds to
var q = orders
.SelectMany(order => order.Lines, (order, orderline) => new { order, orderline})
.Where(item => item.orderline.Count > 10)
.Select(item => item.order.Discount * item.orderline.Price);
For more information on SelectMany, see the MSDN documentation.
If you don't have associations defined:
var q = from order in orders
from orderline in orderLines
where orderline.OrderId == order.Id
where orderline.Count > 10
select order.Discount * orderline.Price;
this more or less corresponds to
var q = orders
.SelectMany(order => orderLines, (order, orderline) => new { order, orderline})
.Where(item => item.orderline.OrderId == item.order.Id)
.Where(item => item.orderline.Count > 10)
.Select(item => item.order.Discount * item.orderline.Price);
I am trying to do a query like:
var a = session.QueryOver<Site>()
.SelectList(
x => x.Select(p => p.SiteName)
.Select(p => p.SiteId).Select(p => p.RegionLocation.City))
.List<object[]>();
but I get the error
could not resolve property: RegionLocation.City of: Entities.Site
The property exists and I can retrieve it using LINQ but QueryOver does not work. What am I doing wrong ?
As far as i remember, with QueryOver, you have to join all entities in the association in order to be able to access it's properties.
This means you ought to do something like:
(notice the .JoinQueryOver)
var a = session.QueryOver<Site>()
.JoinQueryOver(s => s.RegionLocation)
.SelectList(
x => x.Select(p => p.SiteName)
.Select(p => p.SiteId)
.Select(p => p.RegionLocation.City))
.List<object[]>();
Or maybe this will work:
RegionLocation regionLocationAlias = null;
var a = session.QueryOver<Site>()
.JoinAlias(s => s.RegionLocation, () => regionLocationAlias)
.SelectList(
x => x.Select(p => p.SiteName)
.Select(p => p.SiteId)
.Select(() => regionLocationAlias.City))
.List<object[]>();
Also you might want to have a look at https://github.com/davybrion/NHibernateWorkshop/tree/master/NHibernateWorkshop
There's lots of great examples!
Specifically for your problem, have a look at: https://github.com/davybrion/NHibernateWorkshop/blob/master/NHibernateWorkshop/Querying/QueryOver/Projecting.cs