I've made a query using querybuilder. It look likes:
//Create a Querybuilder
$qb = $this->_em->createQueryBuilder();
//Foreach entity, check if it's a join and leftjoin it.
//If there's no join, make it the select
foreach($config['entities'] as $name => $entity)
{
//add new alias(ses) to select statement
$qb->addSelect($entity['alias']);
if(!isset($entity['join'])){
$qb->from($entity['path'], $entity['alias']);
} else {
$qb->leftJoin($entity['join'], $entity['alias']);
}
}
->orWhere(':test IS NULL')
->setParameter('test', 'User\Entity\Address');
//Make the query
$query = $qb->getQuery();
//Return the result
return $query->getResult();
I've made my select and left join dynamically with a config file. So people can make own joins. But when i have (for example) users and addresses. It shows only users WITH addresses. Users without addresses are not show. When i've no join, all users show up. Has somebody an idea about it? I read something like i've to set a where clause and do something like:
->orWhere(':test IS NULL')
->setParameter('test', 'User\Entity\Address');
It doesn't work. How can i have joins AND show all the users also WITHOUT addresses?
Grtz
I've a problem with my where clause. It had a "like" in it, where he wants to like the "street" (from addresses), to something. But when users didn't had a address, he can't like and so he don't show the whole user.
Related
I'm using Typeorm#0.2.5 with MySql driver.
I have an entity, MyEntity, which has a many-to-many relationship with another entity, RelEntity. Therefore Typeorm generates a pivot table of the PKs to create the relationship.
My problem comes from the need to find all MyEntity using a where clause of RelEntity.prop = mySearchKey.
I'm not sure if this is down to me missing some documentation or not fully understanding how to structure this query withing Typeorm.
I believe my SQL statement for this would look something like:
SELECT m.* FROM my_entity_table m
LEFT JOIN my_rel_pivot_table mrp ON mrp.my_entity_id = m.id
LEFT JOIN rel_entity_table r ON r.id = mrp.rel_entity_id
WHERE r.id = {MY_VALUE_HERE}
However, I'm not too sure how to translate this into a Typeorm query.
I have tried:
this.entityRepo.find({
where: {
rel: myValue
}
});
I have also tried:
this.entityRepo.find({
where: {
rel: { id: myValue}
}
});
However, I received the following error:
Unknown column 'MyEntity.myEntityId' in 'where clause'
Has anyone encountered this issue before, or have any idea how to solve this?
I've this working for me, between my articles and categories (many-to-many).
To get my articles that are from a specific category:
this
.entityRepo
.createQueryBuilder('article')
.innerJoin(
'article.categories',
'category',
'category.id = :categoryId',
{ categoryId: XXX }
).getMany();
XXX is the id of the specific category.
Hope it will help you.
After asking for help on GitHub, the answer to the following would be to use the QueryBuilder API.
This can be done such as:
const myEntities = await this.entityRepo.createQueryBuilder("entity")
.leftJoin("relEntity", "relEntity.id = :myId", {myId: myValue})
.getMany()
Many thanks to https://github.com/pleerock for helping me with this.
Many-to-many relations querying
I faced a task, where I needed to do a query for an intermediate table in a many-to-many relationship.
We use a custom soft-delete model, so we needed a way to drop soft-deleted links in an intermediate table.
Basically, what we did, we wrote an extra condition referencing intermediate table name, that is formed like <left-join-alias>_<right-join-alias> and querying there a raw field name as it is in the DB. Here it is STATE_CODE.
const myEntities = await this.entityRepo
.createQueryBuilder('entity')
.leftJoin('entity.manyToManyRel', '"entity_manyToManyRel"."STATE_CODE" != :deleted', {
deleted: 'D'
})
.getMany()
Referencing another table value in a condition
If you want to make a query by another table value, you can do it by referencing its alias and field, if it is an entity table, or by using raw column names, if it is something hidden, like with a many-to-many relationships column.
const myEntities = await this.entityRepo
.createQueryBuilder('entity')
.leftJoin('entity.country', 'country')
.leftJoin('entity.articles', 'articles', 'articles.language = country.language')
.getMany()
I'm using the Yii2 framework for a very basic stock software. I have two tables of a very basic stock software:
products = (id_product, name)
movements = (id_movement, quantity, date)
The products table has all the product of a supermarket.
When the supermarket buy a product, it is registered in the movements table.
I want to show a grid with the current stock in the index.php view. I am thinking to have a actionIndex function to get the total of each products.
Basically I want to do this:
public function actionIndex()
{
Get movements and products from database;
For each product {
if (movement is IN) {
add();
}
else {
subtract();
}
}
return...
}
Using Gii Code Generator, I made a CRUD for products and a CRUD for movements.
So first, I need to get the products and movements from database. Without Yii, I can make a simple JOIN query. But I have no idea how to do it using Yii. What is the best way to do it? I would like to use the query builder.
I found this question but I didn't work for me. And this documentation but I really don't understand it.
You can use innerJoin or similar function
$result= (new Query())
->select('table1.col1, table1.col2,,,, table2.co1, table2.col2 ...')
->from('products ')
->innerJoin('movements', 'product.key= movements.key');
http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html
I am trying to build an alphabetically sorted list of user names from my User objects in the database. Im finding that all the different ways of list() only returns the entire User objects. I just need their usernames which is a property of each User. I need to feed this list to a g:select pull down list on my gsp. Can't seem to put the code together. I am using Mongodb but that shouldn't really matter I know. Here's my algorithm.
Iterate through the user collection and grab the property username on each.
collect all usernames into list then alphabetically sort it
feed it to the g:select list
maybe something like
list userList = User.list()
list usernameList
usernameList << a groovy loop to collect it.username(s)
and then alphabetically sort usernameList then feed it to g:select.
You can (and should) create custom query, just create a hql query and then use the method executeQuery:
http://grails.org/doc/2.3.7/ref/Domain%20Classes/executeQuery.html
User.executeQuery("SELECT username FROM User u order by u.username asc")
Ok here is a shorter way userlist = User.list().collect{it.username}.sort(java.text.Collator.instance)
here is my solution
def usersList = User.list().username.sort()
Here's one possible way to do it:
userlist = User.list()
def userlist2 = []
userlist.each { userlist2 << it.username }
userlist2.sort()
userlist = userlist2
Now userlist is ready as you need it to be fed into g:select
I set up my many-to-many relationship in EF. But I can only refer to the main tables, not the bridge table. How can I refer to the bridge table?
for example:
User: UserID, name
Group: GroupID, group
UserGroup: UserID, GroupID
I can refer to the User table and Group table by typing
context.User.(some linq expression)
context.Group.(some lin1 expression)
But I cannot refer to the bridge table by typing
context.UserGroup
It would be great to know which versions of MVC and EF you are working with. Based on the assumption that its MVC 4 and EF5...
The point of a Join table is to keep referential integrity going. As #timothy says, there is no reason to refer to the (UserGroup) Join table unless there is actual additional data in it i.e. payload. If you're putting other data in the UserGroup table then its not a Join table anyway.
Rather use some Lazy or Eager loading to get the Group data you need:
Lazy Loading
var users = context.Users
foreach (User x in users)
{
foreach (Group f in x.Groups)
//notice the x user being referred to here for Groups
{
// Whatever you want to do with the objects
}
}
Eager Loading
var users = context.Users.Include(g => g.Groups)
foreach (User x in users)
{
foreach (Group f in x.Groups)
//notice the x user being referred to here for Groups
{
// Whatever you want to do with the objects
}
}
The 'foreach' code above is just added to show how to include it in a loop example. Its the first line of these Loading examples that are important.
Once you have defined 'var users' the rest is "easy".
Good Luck!
When defining a many-to-many relationship you have two options.
Link User to Group, and let it know that UserGroup is your join table
Link User to UserGroup as many-to-one, also link Group to UserGroup using many-to-one.
The reason to use option 2 is when you have something other than just the two IDs in the join table. An example I had recently was a SortOrder field.
When querying with a materialized join table, it feels a little clumsy:
context.User.Select(user => new {
Name = user.Name,
Groups = user.GroupJoins
.OrderBy(groupJoin => groupJoin.SortOrder)
.Select(groupJoin => groupJoin.Group.Name)
});
Why you want refer to that junction table...?!
If you want to get Users of a group:
var users = from u in db.UserGroups.Include("User").Include("Group")
Where u.GroupID == gid
select u;
And simply vice versa if you need Groups of a User:
var groups = from g in db.UserGroups.Include("User").Include("Group")
Where g.UserID == uid
select g;
I have two tables User and UserRole which are they connected using a link table UserInRole
When I generate the entity model, for some reason, the entity UserInRole not getting generated. And as you can see from the picture, Entity Framework understood that there is many-to-many relationship between User and UserRole:
I need to implement the query like this
select ur.Name from [User] as u
inner join UserInRole uir on uir.UserId = u.Id
inner join UserRole ur on ur.Id = uir.UserRoleId
where u.Username = 'magename'
I am using generic repository, if navigation property would exists the query would be looking like this:
from u in repository.AsQueryable<User>()
join uir in repository.AsQueryable<UserInRole>() on u.Id equals uir.UserId
join ur in repository.AsQueryable<UserRole>() on uir.UserId equals ur.Id
where u.Username == userName
select ur.Name
But Entity Framework does not generate UserInRoles navigation property and related UserInRole entity, so the question what should I do in that situation? Should I remove link between UserInRole and UserRole to get entity UserInRole generated in model or there any way to have the query I described above without any changes in database?
UPDATED
so looks i need to do something like that
stirng[] roles = (from u in repository.AsQueryable<User>()
where u.Username == userName
select ur.UserRoles.Select(x => x.Name)).ToArray<string>();
getting an error Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.IEnumerable<string>>' to 'string[]' any ideas?
You don't need that link table in your EF model! That's the beauty of EF!!
Check your entity User - it has a UserRoles navigation property - that's the collection of all roles this user is in.
Check out entity UserRole: it has a navigation property Users which has all users that are in this role.
With these two multi-valued navigation properties, you can express any of the queries you might want:
find all users for a given role (find the UserRole entity and enumerate its .Users property)
find all roles for a given user (find the User and enumerate its .UserRoles)
EF and the EDM sort of "hide" that link table from you - you don't really need it when you're expressing your intent in the conceptual model; those link tables are just a "necessary evil" in relational databases since those databases cannot model m:n relationships in any other way.
Update: so you seem to want to find a list of all the user roles (their names) that a particular user is in - you can express this something like this:
// find the user in your "dbContext" (or via your repository)
var user = _dbContext.Users.FirstOrDefault(u => u.Name == "magename");
// from the list of UserRoles on that user, select the names only
var userRolesNames = user.UserRoles.Select(ur => ur.Name).ToList();