LINQ-to-Entity Joined Table Return - entity-framework

I have two tables as follows:
Departments:
DeptID (PK)
DeptName
...
Employees:
EmpID (PK)
DeptID (FK)
EmpName
...
and I have a query using LINQ as follows:
public List<Employee> GetEmployee(int deptID)
{
var query = from e in mdc.Employees
join d in mdc.Departments on e.DeptID equals d.DeptID
where e.DeptID == deptID
select new { e.EmpID, e.EmpName, d.DeptName };
return query.ToList();
}
Now my question is this. I would like to select the fields EmpID, EmpName, and DeptName.
But what will my return type be? This one returns an error because this query returns a GenericList as opposed to my List<Employee>.

You need to create another class with required properties like this,
public class NewType{
public EmpID{get;set;}
//other fields here
}
and then select ,
public List<NewType> GetEmployee(int deptID)
{
var query = from e in mdc.Employees
join d in mdc.Departments on e.DeptID equals d.DeptID
where e.DeptID == deptID
select new NewType{ e.EmpID, e.EmpName, d.DeptName };
return query.ToList();
}

Related

Include with additional param on join

I have many Nations and for each Nation i have a lot of Teams.
The GetTeam endpoint in team controller retrieve a single Team and its related Nation. Via LINQ the query is this:
Context.Teams.Include(t => t.Nation).First(t => t.Id.Equals(__id))
The resulting JSON is what I want:
{"team":{"name":"Team1","nation":{"id":1,"name":"Nation1"}}
Let's say now that the property "name", both in Team and Nation model is dropped and a new model relation is created, with Translation.
What I want now is to retrieve the same JSON, but with a different query based on culture.
Gettin crazy understand how I can achieve it with include.
How can I compose this query in LINQ ?
select *
from Teams inner join
Translations TeamTr on Teams.id = TeamTr .id and TeamTr .culture = "IT" inner join
Nations on Teams.nation_id = Nations.id inner join
Translations NationTr on Nations .id = NationTr .id and NationTr .culture = "IT"
And compose the resulting data as JSON above?
for example:
(from team in Context.Teams
join teamTr in Context.Translations on team.id equals teamTr.id
join nation in Context.Nations on team.nation_id equals nations.id
join nationTr in Context.Translations on nation.id equals nationTr.id
where teamTr.culture == "IT" && nationTr.culture == "IT"
select new
{
teamName = team.name,
nationName = nation.name
}).ToList();
Nice catch tdayi.
First of all I've created a new class, that will be the container of the linq result:
public class TeamDetailLinqDto
{
public Team Team { get; set; }
public Translation TeamTranslation { get; set; }
public Nation Nation { get; set; }
public Translation NationTranslation { get; set; }
}
and this is the linq query:
public IQueryable<TeamDetailLinqDto> GetTeams()
{
var result = from team in Context.Teams
join teamTranslation in Context.Translations on
new { Id = team.Id, Locale = "IT" }
equals new { Id = teamTranslation.EntityId, Locale = teamTranslation.Locale }
join nation in Context.Nations on team.NationId equals nation.Id
join nationTranslation in Context.Translations on
new { Id = nation.Id, Locale = "IT" }
equals new { Id = nationTranslation.EntityId, Locale = nationTranslation.Locale }
select new TeamDetailLinqDto
{
Team = team,
TeamTranslation = teamTranslation,
Nation = nation,
NationTranslation = nationTranslation
};
return result;
}

laravel hasone get name from id

I have a table with:
id
employee_name
manager_id
In this table, manager id is a foreign key to id in same table.
I have another table with projects
id
employee_id
In this table, employee_id is a foreign key to id in the employee table
I try to get the name from the manager_id like this in the controller:
public function show(Employee $managers, $id)
{
$manager = $managers::find($id)->manager;
\Debugbar::info($manager);
}
And my App\Employee file is like this:
class Employee extends Model {
protected $table = 'employees';
public $timestamps = true;
public function projects()
{
return $this->hasMany('App\Projects');
}
public function manager()
{
return $this->hasOne('App\Employee');
}
}
The proble is I get:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'employees.employee_id' in 'where clause' (SQL: select * from `employees` where `employees`.`employee_id` = 1 and `employees`.`employee_id` is not null limit 1)
To me it shows that it is taking employee_id in the sal statement from the other function where it should only take id as it is in the same table.
You should change:
public function manager()
{
return $this->hasOne('App\Employee');
}
into
public function manager()
{
return $this->belongsTo('App\Employee','manager_id');
}
You can do it without the manager_id I expect the 2nd parameter is for when you have an id that does not follow the tablename_id convention.
public function manager()
{
return $this->belongsTo('App\Employee');
}

Entity Framework code first - many to many filtering

Small EF question.
I have a many to many relationship mapped in EF. X..Y
So when I have one X there is a property X.Ys.
Now what I want to do is use a Linq Query to get several X's but I don't want to have all Y's inside the selected X's.
I want the Y's filtered on Y.RegistrationDate > Date.Today.
So when I have one X and itterate through .Y's I will only get future Y's.
UPDATE
This works, resulting in S having distinct ug's with it's relationship only containing upcoming events.
But don't tell me this cant be simplified??!!
var t = (from ug in uof.Ugs.All().ToList()
from upcomingEvent in ug.Events
where upcomingEvent.Date >= DateTime.Today
select new
{
ug,
upcomingEvent
}).ToList();
var s = (from ug in t.Select(x => x.ug).Distinct()
select new UG
{
Id = ug.Id,
Name = ug.Name,
Description = ug.Description,
WebSite = ug.WebSite,
Events = ug.Events.Where(x => x.Date >= DateTime.Today).ToList()
}).ToList();
UPDATE2
Added image to show that even with basic context manipulation I'm still getting 2 events, event when I take 1!
exampledebugimage
EF does not support this scenario as you want it, what you can do however is this:
var date = DateTime.Date;
var query = from x in Xs
select new
{
X = x
Ys = x.Ys.Where(i = > i.RegistrationDate > date)
}
Which will give you a collection of X's with their corresponding Y's that match your criteria.
Have you tried?:
var query = Xs
.Select(x => new { x, yCol = x.YCol.Where(y => y.Date >= DateTime.Today) })
.AsEnumerable()
.Select(x => x.x)
.ToList();
See: http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx
All those .ToList you use will mean you load the whole table from the db before filtering. So watch out for that.
UPDATE: As fixup doesn't work with Many-To-Many
As Slauma mentioned in the comments make sure you don't use this technique if you are going to submit the changes as the changetracking will think you altered the collection. Or even better make sure you use .AsNoTracking() which will improve performance anyway.
We can use the same solution as above but slightly different for many-to-many. See this example:
[TestClass]
public class ContextTest
{
[TestMethod]
public void FixupTest()
{
Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
using (var db = new Context())
{
db.Groups.Add(new Group
{
Name = "G1",
Users = new List<User>{
new User{ Name = "M"},
new User{Name = "S"}
}
});
db.SaveChanges();
}
using (var db = new Context())
{
var group = db.Groups
.Select(g => new { g, Users = g.Users.Where(u => u.Name == "M") })
.AsEnumerable()
.Select(g => {
g.g.Users = g.Users.ToList();
return g.g;
})
.First();
Assert.AreEqual(1, group.Users.Count);
}
}
}
public class User
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Group> Groups { get; set; }
}
public class Group
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<User> Users { get; set; }
}
The test pass and the generated sql is:
SELECT
[Project1].[ID] AS [ID],
[Project1].[Name] AS [Name],
[Project1].[C1] AS [C1],
[Project1].[ID1] AS [ID1],
[Project1].[Name1] AS [Name1]
FROM ( SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Join1].[ID] AS [ID1],
[Join1].[Name] AS [Name1],
CASE WHEN ([Join1].[Group_ID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM [dbo].[Groups] AS [Extent1]
LEFT OUTER JOIN (SELECT [Extent2].[Group_ID] AS [Group_ID], [Extent3].[ID] AS [ID], [Extent3].[Name] AS [Name]
FROM [dbo].[GroupUsers] AS [Extent2]
INNER JOIN [dbo].[Users] AS [Extent3] ON [Extent3].[ID] = [Extent2].[User_ID] ) AS [Join1] ON ([Extent1].[ID] = [Join1].[Group_ID]) AND (N'Mikael' = [Join1].[Name])
) AS [Project1]
ORDER BY [Project1].[ID] ASC, [Project1].[C1] ASC

Problems with selecting 2 column values in Linq to Entity

Hi I am trying to select the values of two columns which are second driver and price but I am getting error: Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Linq.IQueryable'. An explicit conversion exists (are you missing a cast?)
Below is the code:
public IQueryable<Event> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
IQueryable<Event> SecondDriver = from p in entity.Events
where p.ID == eventID
select new{ p.SecondDriver,
p.SecondDriverPrice};
return SecondDriver;
}
Any help or suggestions will be appreciated thnx
You cannot use projection when you expect IQueryable<Event> where Event is your mapped type. You must either select Event :
IQueryable<Event> SecondDriver = from p in entity.Events
where p.ID == eventID
select p;
Or you must create new type and project data to a new type:
public class EventDto
{
public Driver SecondDriver { get; set; }
public Price SecondDriverPrice { get; set; }
}
and redefine your method:
public IQueryable<EventDto> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
IQueryable<EventDto> SecondDriver = from p in entity.Events
where p.ID == eventID
select new EventDto
{
SecondDriver = p.SecondDriver,
SecondDriverPrice = p.SecondDriverPrice
};
return SecondDriver;
}
You cannot return anonymous objects. Try like this:
public IQueryable<Event> GetSecondDriverOption(int eventID)
{
ApextrackdaysEntities entity = new ApextrackdaysEntities();
var seconDriver =
from p in entity.Events
where p.ID == eventID;
select p;
return secondDriver;
}

Construct JPA query for a OneToMany relation

I've those 2 entities
Class A {
#OneToMany(mappedBy="a")
private List<B> bs;
}
Class B {
#ManyToOne
private A a;
private String name;
}
1) I would like to construct a query that says get all A's that have at least one B with name ="mohamede1945"
2) I would like to construct a query that says get all A's that don't have any B with name = "mohamede1945"
Could anyone help me?
First of all, I think you can learn the answer by looking at this link and search for JOIN: http://download.oracle.com/docs/cd/E11035_01/kodo41/full/html/ejb3_langref.html
Second of all, here is my approach:
#Entity
#NamedQueries({
#NamedQuery(name="A.hasBName",query="SELECT a FROM A a JOIN a.b b WHERE b.name = :name"),
#NamedQuery(name="A.dontHasBName",query="SELECT a FROM A a JOIN a.b b WHERE b.name <> :name")
})
Class A { /* as you defined */ }
In you DAO, you can make the namedquery like this:
public List<A> findByHasBName( String name ){
Query q = em.createNamedQuery("A.hasBName")
.setParameter("name", name);
try{
return ( (List<A>) q.getResultList());
} catch ( IndexOutOfBoundsException e){
return null;
}
}
You can use the ANY and ALL constructs to filter the subquery. So something like
1. FROM A aEntity WHERE 'mohamede1945' = ANY (SELECT bEntity.name FROM aEntity.bs bEntity)
2. FROM A aEntity WHERE 'mohamede1945' <> ALL (SELECT bEntity.name FROM aEntity.bs bEntity)