NHibernate Fetch when querying for single object - nhibernate

I'm trying to optimize an NHibernate query:
var profile = dc.Profiles.FirstOrDefault(p => p.IdProfile == idProfile);
I would like it to load a collection of Rights. I did this:
var profile = dc.Profiles.Fetch(x => x.Rights).FirstOrDefault(p => p.IdProfile == idProfile);
The results were totally different from what I expected - instead of getting single Profile with rights I got single profile with single right!
How can I fix it?

You can use like this
var profile = dc.Profiles.Where(p => p.IdProfile == idProfile).Select(x => x.Rights);

Related

Unhandled exception. System.InvalidOperationException: The LINQ expression error by JsonConvert.Deserialize()

I get an error from this code:
var b = content.FormMasterLists.Where(x => x.FormMasterStatus == "pending");
var c = b.Where(x => JsonConvert.DeserializeObject<ApprovalCCB>(x.FormMasterApprovalCcb).Group.SelectMany(x => x.Department).SelectMany(x => x.ApprovalCCBLevel).SelectMany(x => x.Approver).Where(x => x.ApproverEmail == "christ").Any());
But this code runs successfully:
var b = content.FormMasterLists.Where(x => x.FormMasterStatus == "pending").ToList();
var c = b.Where(x => JsonConvert.DeserializeObject<ApprovalCCB>(x.FormMasterApprovalCcb).Group.SelectMany(x => x.Department).SelectMany(x => x.ApprovalCCBLevel).SelectMany(x => x.Approver).Where(x => x.ApproverEmail == "christ").Any());
Is there any way to declare .Where without List()?
Is there any way to declare .Where without List()?
No way in such implementation. EF Core cannot convert JsonConvert.DeserializeObject to the SQL and provide needed filtering on the server side.
So you have to materialise objects to IEnumerable and use client side filtering.
Anyway some databases provide filtering based on JSON content but then you have to create appropriate extension function for EF Core.

How to filter a list of Pages by Category to display as a navigation

In Sitefinity v12.x I would like to create a widget that allows the user to select one or more Categories (Hierarchical Taxons) to use as filter criteria, and after which the widget would query for Pages that have these Categories assigned to them. This seems simple enough on the surface but I can't seem to pull it all together.
I've added "Category" as a Custom Field to the Page data and I've created my test pages. What I'm struggling with is forming the query that can access the custom field "Category" and then compare those against the categories provided by the user.
I've tinkered for awhile but it seems the issue I'm having is retrieving the Categories assigned to a Page from within the Linq query. I've tried var categories = pageNode.GetValue("Category") on it's own and that works as expected. But when I try to use the .GetValue("Category") method in a Linq query this does not seem to be valid, here is an example of what I mean:
var pageManager = PageManager.GetManager();
var pages = pageManager.GetPageDataList().Where(pageData =>
(pageData.Culture == "en" ||
pageData.NavigationNode.LocalizationStrategy != Telerik.Sitefinity.Localization.LocalizationStrategy.Split) &&
pageData.NavigationNode.NodeType == Telerik.Sitefinity.Pages.Model.NodeType.Standard &&
pageData.NavigationNode.RootNodeId == Telerik.Sitefinity.Abstractions.SiteInitializer.CurrentFrontendRootNodeId &&
pageData.Status == ContentLifecycleStatus.Live)
.Select(x => x.NavigationNode);
foreach (PageNode page in pages)
{
// This properly retrieves Categories assigned to a Page in the Debug window
var categories = page.GetValue("Category");
}
// This does not work, error message below .Any() reads: 'object' does not contain a definition for 'Any' and no accessible extension method 'Any' accepting a first argument of type 'object' could be found
var categoryPages = pages
.Where(pageData => pageData.GetValue("Category").Any())
.ToList();
Is there a way I can use/access the Custom Field "Category" on a Page from within a Linq query? Or do I have to go about this some other way?
Thank you in advance for any guidance!
As a note, don't forget to filter the pages for visible and not deleted.
pageData.Status == ContentLifecycleStatus.Live && pageData.IsDeleted == false && pageData.Visible == true)
You should cast pageData.GetValue("Category") to either Guid? or IEnumerable<Guid?> depending how exactly you have set the custom field up.
Thank you for the tips everyone! I was able to sort it out by specifying the type of the Custom Value in the Linq query, like so: pageData.GetValue<TrackedList<Guid>>("Category"), here's what I came up with:
var pageManager = PageManager.GetManager();
var pages = pageManager.GetPageDataList().Where(pageData =>
(pageData.Culture == "en" ||
pageData.NavigationNode.LocalizationStrategy != Telerik.Sitefinity.Localization.LocalizationStrategy.Split) &&
pageData.NavigationNode.NodeType == NodeType.Standard &&
pageData.NavigationNode.RootNodeId == Telerik.Sitefinity.Abstractions.SiteInitializer.CurrentFrontendRootNodeId &&
pageData.Status == ContentLifecycleStatus.Live && pageData.Visible == true)
.Select(x => x.NavigationNode);
var filteredPages = pages
.Where(pageData => categoriesQuery.All(c => pageData.GetValue<TrackedList<Guid>>("Category").Contains(c)))
.ToList();

Nhibernate Restrictions.In Error

Finally tracked down my error which is a result of the query. I have an nhibernate query using a Restrictions.In. Problem is once query executes if no results returned query throws error immediately. Is there another restriction that I can use. I know if I was writing a linq query I could use the .Any to return bool value and go from there is there something similar I can do in this instance?
carMake is passed in
myQuery.JoinQueryOver(x => x.Car)
.Where(Restrictions.In("VIN",
Trades.Where(x => x.Car.Make.ToLower() == carMake.ToLower())
.Select(x => x.Car.PrimaryVIN)
.ToList()));
Assuming that Trades is a list of objects you can use .WhereRestrictionOn() instead. Try this (I split the code for better readability):
var vinsWithCarMake = Trades
.Where(x => x.Car.Make.ToLower() == carMake.ToLower())
.Select(x => x.Car.PrimaryVIN)
.ToList<string>();
var carAlias = null;
var result = myQuery.JoinAlias(x => x.Car, () => carAlias)
.WhereRestrictionOn(() => carAlias.VIN).IsInG<string>(vinsWithCarMake)
.List();

Linq Many to many

Could anyone please help with the linq for this problem.
Users have a list of Properties and Properties have a list of Users.
I first do a query to get all Properties with a particular CompanyId. This makes a new list which we'll call MyProperties.
I need to get all Tenants that have a property in the MyProperties list.
For other reasons, I don't have access to the "PropertiesUsers" Join table.
Sorry if it looks like I haven't thought this through, I've been banging my head all day on it.
You can use Enumerable.SelectMany() to flatten the hierarchy:
var myProperties = dbContext.Properties.Where(property => property.CompanyId = companyId);
var tenants = myProperties.SelectMany(property => property.Tenants);
Use Intersect:
var myPropertyIds = MyProperties.Select(p => p.PropertyId).ToArray();
var result = Users.Where(u => myPropertyIds.Intersect(
u.Properties.Select(p => p.PropertyId))
.Any());
If you are sure that the properties in both lists are the same instances you could use
var result = Users.Where(u => MyProperties.Intersect(
u.Properties)
.Any());

nhibernate queryover not loading eagerly with a many to many joinalias

I'm trying to eager load roles in many to many collection off of my User object.
Role role = null;
IQueryOver<User, User> query = session.QueryOver<User>()
.Fetch( p => p.Roles).Eager
.JoinAlias( q => q.Roles, () => role)
.Where(() => role.Active == true);
leaves me with user objects that have uninitialized roles members. If I remove the joinalias, they are initialized just fine. Is this just an NH3 bug or am I doing something wrong?
Another way to make eager load is to set LeftOuterJoin. It helped to us in a similar scenario
Role role = null;
IQueryOver<User, User> query = session.QueryOver<User>().Fetch( p => p.Roles).Eager
.JoinAlias( q => q.Roles, () => role, JoinType.LeftOuterJoin)
.Where(() => role.Active == true);
That's the expected behavior. If you use JoinAlias, you'll be filtering the collection elements, so it can't be initialized.
You need to use a subquery for filtering if you intend to use eager loading. on the same collection.