Cayenne JOIN expression - postgresql

I've been trying to do a join query with cayenne but I'm getting stuck with the use of Expressions and that.
In sql it would be something like this:
SELECT *
FROM usuarios, rol, user_rol
WHERE usuarios.cod_usuario = user_rol.cod_usuario
AND user_rol.cod_rol = rol.cod_rol
This would be the basic.
Thanks in advance

The answer to that, just like with the other question that you had is to use relationships. Once you map the relationships between Usuarios / UserRol and UserRol / Rol, you can either traverse the relationship from the user object by calling its methods:
Usuarios u = ..
for(UserRol ur : u.getUserRols()) {
Rol r = ur.getRol();
// now do something with it
}
Or find Rols with a query matching that user:
SelectQuery query = new SelectQuery(Rol.class);
query.andQualifier(ExpressionFactory.matchExp("userRol.user", u);
List<Rol> roles = context.performQuery(query);
Path argument of 'ExpressionFactory.matchExp' (i.e. "userRol.user" String) should be adjusted to match the actual relationship names starting at the Rol entity (as Rol is the root of the query), going to UserRol, and from that to Usuarios.

Related

Query many to many relationship in Linq and EFCore

I'm trying to do the following query in linq, however I'm getting an exception error, though my query looks fine to me. So here is the story:
Diagram
I have a many to many relationship between the users and the organizations. A user can be a part of many organizations, and an organization can have many users.
What Im trying to query
So given a user id, i want to query all the team members (users) i have in all the organizations i belong to. So
Input: User X id (guid), and this user belongs to Organization A, and Organization B
Output:
User A, Organization A
User B, Organization A
User C, Organization B
The Actual Query
I though this would do just that
var user = db.Users.Include(q => q.UserOrganization).SingleOrDefault( q => q.Id == id.ToString());
var members = (from us in db.Users.Include(q => q.UserOrganization)
let orgs = user.UserOrganization.Select(z => z.OrganizationId)
where us.UserOrganization.Any(q => orgs.Contains(q.OrganizationId) )
select new UserResource{
id = Guid.Parse(us.Id),
email = us.Email
}
).ToArray();
My query fails on the where clause, with the error:
Processing of the LINQ expression 'AsQueryable<long>((Unhandled parameter: __Select_0))' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core
Not sure what to change in the query. Please help.
PS: I wrote the query initially in MySql as follows:
SELECT UU.`Id`, UU.`Email`, UUO.`OrganizationId`
FROM aspnetusers AS UU
LEFT JOIN userorganization AS UUO ON UUO.`UserId` = `UU`.Id
WHERE UUO.`OrganizationId` IN
(
SELECT UO.`OrganizationId` FROM aspnetusers AS U
LEFT JOIN userorganization AS UO ON UO.UserId = U.Id
WHERE u.Id = '6caa67e7-69f3-49a3-ad61-10b07d379f10'
)
AND UU.Id != '6caa67e7-69f3-49a3-ad61-10b07d379f10'
The "SingleOrDefault" always executes the Query. User is not an IQueryable.
So the let orgs = user.UserOrganization.Select(z => z.OrganizationId) cannot be translated to SQL, do your var orgs = user.UserOrganization.Select(z => z.OrganizationId) before the Query, in Plain C#. This cannot be used in SQL-Queries.
With orgs being an IList<int> it will work.
But it should be prefered to find a solution that can be solved with one query only. Here you have two.
The SingleOrDefault might be not useful, you go better without, than you have a simple IQueryable. And The "Any" can most often be realized with a simple (Inner) Join, returning only values, if you have a match between to tables. That is the Same as Where - Any - Contains

linq nested query conditional order by

I have a parent query with sub query return child ,
what i need to sort child query according to one property in parent.
here is sudo code:
from menu in db.Menus
orderby menu.Order
select new
{
Title= menu.Title,
OrderNumber = menu.Order,
data = (from menuItem in menu.Items
let g = Guid.NewGuid()
orderby g
select new
{
id = worker.ID,
Title = worker.JobTitle
})
.Take(4)
};
that works ok,But what i need to sort some menu in random(NewGuid) and sort others with their item priority some thing like it:
let g = Guid.NewGuid()
orderby menu.ISRandom ? g: menuItem.Order
But it give error about mismatch guid and int.What's the soloution?
second:How can i replace take(4) with take(menu.size)?
thank's
You can solve the ordering problem by adding ToString():
let g = Guid.NewGuid().ToString()
orderbymenu.ISRandom ? g : menuItem.Order.ToString()
Using Take(someProperty) isn't allowed in an EF LINQ query. This is because the take is translated into a TOP(x) clause, which can't possibly refer to a column in the SQL result. You can only do this afterwards, after pulling the results into memory without Take (or taking some reasonable fixed maximum).
It seems you want to read four records from menu.Items at random.
I think you'd be way better off just reading all the items, and then doing the random selection later in code in memory.

LINQ to Entities does not recognize the method with Let Statement

I am in the process of converting an application that uses LINQ to SQL over to LINQ to Entities. I use a repository pattern and I have run in a problem that works in LINQ to SQL but not Entities.
In my data layer, I use LINQ statements to fill my object graph so that none of my database entities are exposed anywhere else. In this example, I have a Lookup Respository that returns a list of Categories. It looks like this:
public IQueryable<Entities.DomainModels.Category> getCategories()
{
return (from c in Categories
where !c.inactive
orderby c.categoryName
select new Entities.DomainModels.Category
{
id = c.categoryID,
category = c.categoryName,
inactive = c.inactive
});
}
Later, I want to put the categories into a sub query and it looks like this:
var d = from p in Programs
let categories = (from pc in p.Categories
join c in getCategories() on pc.categoryID equals c.id
select c)
select new
{
id = p.id,
title = p.title
categories = categories.ToList()
};
When I run this, I get the following error:
LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[Entities.DomainModels.Category] getCategories()' method, and this method cannot be translated into a store expression.
For reference, the following works though it doesn't return the data I need (it's basically a join):
var q = from p in Programs
from pc in p.Categories
join c in getCategories() on pc.categoryID equals c.id
select new
{
id = p.id,
category = c
};
I understand what the error means in concept however LINQ to SQL would make it work. I have this pattern throughout my data layer and I really want to keep it. Should this be working? If not, how can I modify it without mixing my layers.
You cant pass getCategories() to EF.
The query must be destructible to expression tree.
Calculate getCategories() first.
eg
var simpleList = getCategories().Select(id).Tolist;
then use a contains
where(t=> simpleList.Contains(t.CatId) // or the query syntax equivalent

WHERE parameter equals ANY column (Entity attribute) value

I need to write a generic NamedQuery; such as, find me all the objects where any of the attributes matches the given parameter.
select mo from MyObject mo where mo.ANYAttribute = someParameter
I could not figure out the expression for "where mo.ANYAttribute". The sort of wildcard such as " + or * or ANY or .)... Something that will save me from writing query where I have to write manually to check for each attribute such as:
where mo.attribute1= :someParameteror or mo.attribute2 = :someParameter
I am using JPA 2.0.
Is it possible this way or I have to change my approach?
Many Thanks,
Nav
You need to list all attributes of an entity, there is no such thing as ANYAttribute in JPA:
where mo.attr1=:someParamter or mo.attr2=:someParameter etc.
Here is an example of #NamedQuery usage with parameters:
Annotate your entity with:
#NamedQuery(name = "findEntityById",
query = "SELECT entity FROM Entity entity WHERE entity.id = :inputId")
Entity manager usage:
Query namedQuery = entityManager.createNamedQuery("findEntityById");
namedQuery.setParameter("inputId", 1);
A very good tutorial on NamedQueries.

Entity Framework: selecting from multiple tables

I have a statement:
var items = from e in db.Elements
join a in db.LookUp
on e.ID equals a.ElementID
where e.Something == something
select new Element
{
ID = e.ID,
LookUpID = a.ID
// some other data get populated here as well
};
As you can see, all I need is a collection of Element objects with data from both tables - Elements and LookUp. This works fine. But then I need to know the number of elements selected:
int count = items.Count();
... this call throws System.NotSupportedException:
"The entity or complex type 'Database.Element' cannot be constructed in a LINQ to Entities query."
How am I supposed to select values from multiple tables into one object in Entity Framework? Thanks for any help!
You are not allowed to create an Entity class in your projection, you have to either project to a new class or an anonymous type
select new
{
ID = e.ID,
LookUpID = a.ID
// some other data get populated here as well
};
Your code doesn't work at all. The part you think worked has never been executed. The first time you executed it was when you called Count.
As exception says you cannot construct mapped entity in projection. Projection can be made only to anonymous or non mapped types. Also it is not clear why you even need this. If your class is correctly mapped you should simply call:
var items = from e in db.Elements
where e.Something == something
select e;
If LookupID is mapped property of your Element class it will be filled. If it is not mapped property you will not be able to load it with single query to Element.