Linq Query across 3 tables - linq

My Domain model is as follows:
User { Id, FirstName, LastName, TeamId }
Team { Id, Name, Description }
Topic { Id, Title, UserId }
My application logic says that a user should be able to view all topics within his/her team.
Knowing the above, how can I write a linq query that will get all topics that have been made by people on the same team as the user?
I have tried the following, but it is obviously wrong, and I just can't see through the logic for the linq query :(
var topicList = (from u in context.Users
join t in context.Topics on u.Id equals t.UserId
where u.TeamId == id
select new Tourist.WEB.Models.TopicListViewModel
{
Id = t.Id,
Title = t.Title,
TopicAuthor = u.FirstName,
NoOfReplies = 3
}).ToList();

like this:
from u in context.Users
join t in context.Team on u.TeamId equals t.Id
join to in context.Topic on u.id equals to.UserId
where u.TeamId == id
Complete query:
var topicList = (from u in context.Users
join t in context.Team on u.TeamId equals t.Id
join to in context.Topic on u.id equals to.UserId
where u.TeamId == id
select new Tourist.WEB.Models.TopicListViewModel
{
Id = to.Id,
Title = to.Title,
TopicAuthor = u.FirstName,
NoOfReplies = 3
}).ToList();

Related

Hibernate CriteriaQuery where - ManyToOne field

that's fragment of my Employee entity/class:
#Entity
#Table
public class Employee {
...
#ManyToOne(.....)
#JoinColumn(name="department_id")
private Department department;
}
Now, I want to fetch all Employees from specific Department (employees with specific department_id):
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = builder.createQuery(Employee.class);
Root<Employee> employeeRoot = criteriaQuery.from(Employee.class);
criteriaQuery.select(employeeRoot);
criteriaQuery.where(builder.equal(employeeRoot.get(????????????), id));
There's my problem. How do I access Department.id? I know i have to get({specific field}) but i dunno how. Should I somehow join those tables first? Looking forward for your answers!
You need create a join with your relationed table.
Ex:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = builder.createQuery(Employee.class);
Root<Employee> employeeRoot = criteriaQuery.from(Employee.class);
Join<Employee, Departament> join = from.join("department", JoinType.INNER);
criteriaQuery.where(builder.equal(join.get("specific_fied"), your_specific_fied));
TypedQuery<Employee> typedQuery = session.createQuery(criteriaQuery);
List<Employee> employees = typedQuery.getResultList();
for (Employee e : employees) {
System.out.println(e.getName());
}
session.getTransaction().commit();
session.close();
entityManagerFactory.close();
If you want anything same as this query:
SELECT c, p.name FROM Country c LEFT OUTER JOIN c.capital p
you can build this:
CriteriaQuery<Country> q = cb.createQuery(Country.class);
Root<Country> c = q.from(Country.class);
Join<Country> p = c.join("capital", JoinType.LEFT);
q.multiselect(c, p.get("name"));
If you what build anything same as this query:
SELECT c FROM Country c JOIN FETCH c.capital
you can build this:
CriteriaQuery<Country> q = cb.createQuery(Country.class);
Root<Country> c = q.from(Country.class);
Fetch<Country,Capital> p = c.fetch("capital");
q.select(c);
For more exemples see FROM clause (JPQL / Criteria API)

LINQ - join with OR condition

I've got two entities, Users and Friendships which look like:
public class User
{
public int UserId { get; set; }
(...)
}
public class Friendship
{
public int SenderId { get; set; }
public int ReceiverId { get; set; }
(...)
}
And I would like to create simple query which in SQL would look like:
SELECT * FROM Users as U
INNER JOIN Friendships as F ON U.UserId = F.ReceiverId OR U.UserId = F.SenderId
Where U.Nick != VARIABLE
In other words I would like to select all friends of the user.
And I can't accomplish that. I've found solution where one creates two separate join queries with union and it works - but it's not efficient to create such query to db.
Joins in LINQ are always equijoins. Basically you need multiple from clauses and a where clause:
var query = from u in db.Users
where u.Nick != variable
from f in db.Friendships
where u.UserId == f.ReceiveId || u.UserId == f.SenderId
select ...;
Now in LINQ to Objects there are probably more efficient ways of doing this - but I'd expect a SQL-based LINQ provider to generate a query which has a good enough execution plan. It may not actually create a JOIN in the SQL, but I'd expect it to be the same execution plan as the join you've shown.
Simply write:
from U in db.Users
from F in Friendships.Where(x => U.UserId == F.ReceiverId || U.UserId == F.SenderId)
where U.Nick != VARIABLE
select new {u, f};

showing multiple rows from database in datagridview using entity framework

I am trying to show multiple records from database in datagridview but I'm having only a single record all the time.
2 tables are involved in this query, from 1st table I acquire all the id's those fulfill the condition and from 2nd table I am getting the user information.
1st table is tblUsers_Roles and 2nd is tblUsers.
These tables have primary/foriegn key relationship.
Here is my code:
IEnumerable<tblUsers_Role> id = db.tblUsers_Role.Where(a => a.User_Role == selectRole);
foreach (var user in id)
{
var userinfo = from b in db.tblUsers
where b.User_Id == user.User_Id
select new { b.First_Name, b.Last_Name, b.Status, b.Authenticated };
dgvResults.DataSource = userinfo.ToList();
dgvResults.Show();
}
You are assigning the grid in the loop. That is not going to work. Maybe something like this will work:
var userinfo =(from ur in db.tblUsers_Role
join u in db.tblUsers
on ur.User_Id equals u.User_Id
where ur.User_Role == selectRole
select new
{
u.First_Name,
u.Last_Name,
u.Status,
u.Authenticated
}).ToList();
dgvResults.DataSource = userinfo;
dgvResults.Show();
Or a alteretive would be like this:
var roles=db.tblUsers_Role
.Where(a => a.User_Role == selectRole)
.Select (a =>a.User_Id).ToList();
var userinfo=
(
from u in db.tblUsers
where roles.Contains(u.User_Id)
select new
{
u.First_Name,
u.Last_Name,
u.Status,
u.Authenticated
}
).ToList();
dgvResults.DataSource = userinfo;
dgvResults.Show();
Not as nice as the first one. But maybe you understand the concept.

Linq distinct problem

I am new to using LINQ, right now i have a query in sql with multiple inner joins and it works fine. I am trying to change this to a equivalent LINQ code, i could able to implement LINQ except for the Distinct fact i am using in my query...
my query
select DT.[Name], count(distinct([FeatureControlID])) as [Value], DT.[Weight]
from [DocumentTypes] DT inner join
[DocumentTypesSchema] DTS on
DT.[ID] = DTS.[DocumentTypeID] inner join
ProductsFeaturesControlsDocumentValues [PFCDV] on
DTS.[ID] = PFCDV.[SchemaID]
where [PFCDV].[ProductID] = 72
group by DT.[Name], DT.[Weight], [DT].[ID]
order by [DT].[ID]
and my LINQ without the Distinct condition is as below
from dt in db.DocumentTypes
join dts in db.DocumentTypesSchemas on new { ID = dt.ID } equals new { ID = dts.DocumentTypeID }
join pfcdv in db.ProductsFeaturesControlsDocumentValues on new { ID = dts.ID } equals new { ID = pfcdv.SchemaID }
where
pfcdv.ProductID == 72
group new {dt, pfcdv} by new {
dt.Name,
dt.Weight,
dt.ID
} into g
orderby
g.Key.ID
select new {
g.Key.Name,
Value = (Int64?)g.Count(p => p.pfcdv.FeatureControlID != null),
Weight = (System.Decimal?)g.Key.Weight
}
can anyone give me a hand on this? actually the linq code executes without the Distinct feature i used in the code.
Have you tried something like this?
...
select new {
g.Key.Name,
Value = (Int64?)g.Select(p => p.pfcdv.FeatureControlID)
.Where(id => id != null)
.Distinct().Count()
Weight = (System.Decimal?)g.Key.Weight
}

How to use join to make this queries cleaner?

I have the feeling that using joins could make this cleaner
public override string[] GetRolesForUser(string username)
{
using (TemplateEntities ctx = new TemplateEntities())
{
using (TransactionScope tran = new TransactionScope())
{
int userId = (from u in ctx.Users
where u.UserName == username
select u.UserId).Single();
int[] roleIds = (from ur in ctx.UserInRoles
where ur.UserId == userId
select ur.RoleId).ToArray();
string[] roleNames = (from r in ctx.Roles
where roleIds.Contains(r.RoleId)
select r.RoleName).ToArray();
tran.Complete();
return roleNames;
}
}
}
You should be able to use the navigation properties to follow the relations instead of using the primary keys (Entity Framework will join behind the scenes for you)
If you have (and need) UserInRoles because there are other properties defined on the junction table, you can use:
return (from u in cts.Users
from ur in u.UserInRoles
from r in ur.Roles
select r.roleName).ToArray();
Otherwise make sure the N-M relation is mapped as such, and don't map the junction table. Then you can just use:
return (from u in cts.Users
from r in u.Roles
select r.roleName).ToArray();
I'm not a c# guy, but essentially you would want to do
select u.userId, ur.roleId, r.roleName
from Users u, UserInRoles ur, Roles r
where u.userId = ? and ur.userId = u.userId and r.roleId = ur.roleId;
You can also use the in syntax if you opt for nested queries.
ie: where user_id in (select userId from UserInRoles)

Resources