Inner join to LINQ - c#

I am new to Linq. For the learning perspective, I am trying to convert this following sql query to linq query. However, this gives me nothing. No error message or anything. The sql query gives me the table but linq doesn't give me values.
The SQL query:
SELECT
Members.FirstName,
Members.LastName,
PhoneScreens.BaselineEligibility
FROM
Members INNER JOIN PhoneScreens ON Members.Id = PhoneScreens.MemberId
WHERE PhoneScreens.BaselineEligibility = 'eligible'
And the Linq query is:
context.Members
.Include(p => p.PhoneScreens)
.Where(y => y.PhoneScreens.BaselineEligibility == "eligible")
.ToListAsync();
EDIT:
Here are the classes:
public class Member
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<PhoneScreen> PhoneScreens { get; set; }
public Member()
{
PhoneScreens = new Collection<PhoneScreen>();
}
}
public class PhoneScreen
{
public string BaselineEligibility { get; set; }
public Member Member { get; set; }
public int MemberId { get; set; }
}
I would appreciate any help.

This will do the work:
context.Members
.Include(c => c.PhoneScreens)
.Where(m => m.PhoneScreens.Any(i => i.BaselineEligibility == "eligible"))

Related

Linq with Lambda - how do I restrict joined table rows?

I want to use Linq to duplicate this T-SQL query on a sports teams database, to look up the experienced players in handball teams:
Select TE.TeamName, PL.FirstName, PL.LastName
From T_Team as TE
Inner Join T_Player As PL
On PL.Team_ID = TE.Team_ID
And PL.ExpLevel = 'Experienced'
Where TE.SportName = 'Handball'
I've tried creating two entities for my two tables:
public class TTeam
{
public int TeamId { get; set; }
public string TeamName { get; set; }
public string SportName { get; set; }
public virtual List<TPlayer> TeamPlayers { get; set; }
// Called in the context OnModelCreating() method
public static void CreateModel(EntityTypeBuilder<TTeam> p_ebpTable)
{
p_etbTable.ToTable("T_TEAM");
p_etbTable.HasKey(t => new { t.TeamId }).HasName("PK_TEAMID_T_TEAM");
// Column definitions
// Foreign Keys
p_etbTable.HasMany(t => t.TeamPlayers).
WithOne(p => p.CurrentTeam).
HasPrincipalKey(t => t.TeamId).
HasForeignKey(p => p.TeamId);
}
}
and
public class TPlayer
{
public int PlayerId { get; set; }
public int TeamId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string ExpLevel { get; set; }
public virtual TTeam CurrentTeam { get; set; }
// Called in the context OnModelCreating() method
public static void CreateModel(EntityTypeBuilder<TPlayer> p_ebpTable)
{
p_etbTable.ToTable("T_PLAYER");
p_etbTable.HasKey(t => new { t.PlayerId }).HasName("PK_PLAYERID_T_PLAYER");
// Column definitions
// Foreign Keys
p_etbTable.HasOne(p => p.CurrentTeam).
WithMany(t => t.TeamPlayers).
HasForeignKey(p => p.TeamId).
HasPrincipalKey(t => t.TeamId);
}
}
then use them in
using Microsoft.EntityFrameworkCore;
IEnumerable<TTeam> z_enbHandballTeams = z_dbcDbContext.TTeamRepository
.Where(te => te.SportName == "Handball")
.Include(te => te.TeamPlayers.Where(pl => pl.ExpLevel == "Experienced"));
but looping through z_enbHandballTeams in a foreach, throws an InvalidOperationException with the message "Lambda expression used inside Include is not valid".
(I guess it goes without saying that ExpLevel is a number and SportName is actually SportId, but I felt it would look easier to read that way.)
What am I doing wrong?
EF Core 3.1.x do not support filtered Include. Workaround is to do that via Select
var z_enbHandballTeams = z_dbcDbContext.TTeamRepository
.Where(te => te.SportName == "Handball")
.Select(te => new TTeam
{
TeamId = te.TeamId,
TeamName = te.TeamName,
SportName = te.SportName,
TeamPlayers = te.TeamPlayers.Where(pl => pl.ExpLevel == "Experienced")
.ToList()
});

Query inner records in ElasticSearch Nest C#

I have structure like this:
public class OuterResource
{
public int Id { get; set; }
[Nested]
public List<InnerResource> InnerResources { get; set; }
}
public class InnerResource
{
public int Id { get; set; }
public int OuterResourceId { get; set; }
public int Value { get; set; }
}
Inner records are stored as lists inside outer records. I want to query inner records, giving specified outer resource id and value to filter inner records.
How to do it in C# Nest? Can't figure it out from documentation.
Please try this.
objforOuterResource.InnerResources.Where(x => x.Id == 5);
.Query<OuterResource>.Nested(n => n
.Path(p => p.InnerResources)
.Query(qq => qq
.Terms(t => t.Fields(fi => fi.InnerResources.First().OuterResourceId ).Terms(value))
)
)
Should work. Note the .First is applied to all the array (=list)

Get columns from Tables (Using Inner Join) with DetachedCriteria (prefereable) or QueryOver

I'm having a problem with my query in NHibernate With DetachedCriteria (or using Session QueryOver). I need to get only a few columns from each table, like the classes as follow:
public class PanelaCorrida : BaseEntity
{
public virtual Int64? CodCorrida { get; set; }
public virtual Int64 NumLocal { get; set; }
public virtual Boolean IdcInspecionada { get; set; }
public virtual String Sigla { get; set; }
public virtual String Rota { get; set; }
public virtual Local Local { get; set; }
public virtual Panela Panela { get; set; }
}
public class Panela : BaseEntity
{
public Panela()
{
this.Local = new Local();
this.PanelaCorridas = new List<PanelaCorrida>();
}
public virtual Int32 Numero { get; set; }
public virtual Boolean IdcAtiva { get; set; }
public virtual Int16 Status { get; set; }
public virtual ICollection<PanelaCorrida> PanelaCorridas { get; set; }
public virtual Local Local { get; set; }
#endregion
}
public class Local : BaseEntity
{
public Local()
{
this.PanelaCorridas = new List<PanelaCorrida>();
this.Panelas = new List<Panela>();
}
#region Property
public virtual Int32 IdLocal { get; set; }
public virtual Int32 AreaLocal { get; set; }
public virtual String Descricao { get; set; }
public virtual String Codigo { get; set; }
#endregion
}
Basically, the Entity 'Panela' is the Mother of 'PanelaCorrida' (Each Panela can have multiple PanelaCorrida's) but a 'PanelaCorrida' can be in one Local. But one local can have multiple PanelaCorrida's as well. It's basically, this relationship:
Panela 1 - N PanelaCorrida
Local 1 - N Panela
Local 1 - N PanelaCorrida
For this query, i need to get the Last PanelaCorrida of the db, but i need the info of Panela and Local as well.
So far, i can get all data using this NHibernate query:
To get all id's of 'panela' which is active:
var panelaIdList = Session.QueryOver<Panela>()
.Select(c => c.Id)
.Where(c => c.IdcAtiva == true)
.List<Int64>();
To get all last id's of 'PanelaCorrida' which is active (and the last PanelaCorrida generated):
var corridaPanelaIdList = Session.QueryOver<PanelaCorrida>()
.Select(
Projections.Max<PanelaCorrida>(x => x.Id),
Projections.Group<PanelaCorrida>(x => x.Panela)
)
.Where(p => p.Panela.IsIn(panelaIdList.ToArray()))
.List<Object[]>();
Now, to get the result with all info of all those tables:
With DetachedCriteria:
criteria = DetachedCriteria.For<PanelaCorrida>()
.CreateAlias("Local", "L")
.CreateAlias("Panela", "P")
.Add(Restrictions.In("Id", corridaPanelaIdList.Select(x => x[0]).ToArray()));
With Session QueryOver:
var corridas = Session.QueryOver<PanelaCorrida>()
.Where(p => p.Id.IsIn(corridaPanelaIdList.Select(x => x[0]).ToArray()))
.List<PanelaCorrida>();
But the problem is, i need only a few columns of each Table. With NHibernate i've tried with Projections, and with QueryOver, i've tried with SelectList, but each time they generate a error (could not found the property of ...) or they do not populate the entities in result.
How i could achieve this?
Note: This is my query in first place (in SQL):
select cd.num_panela_corrida, cd.num_panela, p.numero, l.num_local from scp_panela_corrida cd
inner join scp_panela p on p.num_panela = cd.num_panela
inner join scp_local l on l.num_local = cd.num_local and cd.num_panela_corrida
in (
select
max( c.num_panela_corrida) as num_panela_corrida
from
scp_panela_corrida c
inner join
scp_panela p on p.num_panela = c.num_panela
and p.num_panela in (
select
num_panela
from
scp_panela
where
idc_ativa = 1
) group by c.num_panela ) order by cd.num_panela_corrida desc
But the client don't want to use a Stored Procedure or HQL.
Any help is welcome.
Resolved with the following code (provided with the link of Radim Kohler).
Radim, if you want, please answer this question with the provided link and i'll accept it as the answer. Thanks for your help.
Panela panela = null;
Local local = null;
var query = session.QueryOver<PanelaCorrida>()
.JoinAlias(c => c.Panela, () => panela)
.Where (c => c.Id.IsIn(corridaPanelaIdList.ToArray()))
.SelectList(list => list
.Select(c => c.Id))
.Select(c => c.CodCorrida)
.Select(Projections.Property(() => panela.Id).As("Panela.Id"))
.Select(Projections.Property(() => panela.IdcAtiva).As("Panela.IdcAtiva"))
.TransformUsing(Transformers.AliasToBean(typeof(PanelaCorrida)));
Don't know if is the best approach, but it worked. We will analyze best approaches using QueryOver/DetachedCriteria, but for now, this works great.
Note: I've removed some columns, just to explain how it worked.
Thanks again.

How to convert this SQL to LINQ in C#?

I have a query in SQL query as like below:
with pagedetail as
(
select
c.componentrefid, l.name, c.startdate,
ROW_NUMBER() over(PARTITION By c.componentrefid order by c.startdate desc) as rownumber
from
FM_componentTransaction as c
inner join
FM_LK_statusinfo as l on c.Statusinforefid = l.refid
inner join
fm_scriptinfo as s on s.Refid = c.ScriptRefId
where
s.CustomerInfoRefId = '85629125-7072-4EFE-9201-97E088E126C6'
)
select
pd.*
from
pagedetail pd
where
pd.rownumber = 1
I can get the output of this. Now my questions is how to implement this query using Entity Framework?
I know this is not a direct answer to your question, however one approach would be to create a stored procedure in SQL, and then just call the stored procedure in Entity Framework.
Code first:
How to call Stored Procedure in Entity Framework 6 (Code-First)?
Database First:
https://msdn.microsoft.com/en-us/data/gg699321.aspx
Assuming you have the following model:
public class ComponentTransaction
{
public Guid componentrefid { get; set; }
public string name { get; set; }
public DateTime startdate { get; set; }
public Guid Statusinforefid { get; set; }
public Guid ScriptRefId { get; set; }
}
public class Statusinfo
{
public Guid refid { get; set; }
}
public class Scriptinfo
{
public Guid refid { get; set; }
public Guid CustomerInfoRefId { get; set; }
}
The code can look like this:
Db db = new Db();
Guid customerInfoRefId = new Guid("85629125-7072-4EFE-9201-97E088E126C6");
var res = db.ComponentTransactions
.GroupBy(c => c.componentrefid)
.Select(g => g.OrderByDescending(c => c.startdate).First())
.Join(db.Statusinfos, c => c.Statusinforefid, l => l.refid, (c, l) => c)
.Join(db.Scriptinfos.Where(s => s.CustomerInfoRefId == customerInfoRefId),
c => c.ScriptRefId, s => s.refid, (c, s) => c);

Selecting Entity Using Linq query with join and including nested property

I'm battling to retrieve a single Model/Entity using EntityFramework and Linq.
I have a Business with Members, I'm trying to retrieve the users' business based on the BusinessMembers table/entity.
I have the following entities/models:
public partial class Business
{
public Business()
{
BusinessMembers = new HashSet<BusinessMember>();
}
public int ID { get; set; }
public int ID_BusinessStatus { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Phone { get; set; }
public virtual BusinessStatus BusinessStatus { get; set; }
public virtual ICollection<BusinessMember> BusinessMembers { get; set; }
}
and
public partial class BusinessStatus
{
public BusinessStatus()
{
Businesses = new HashSet<Business>();
}
public int ID { get; set; }
[Required]
[StringLength(3)]
public string Code { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
public virtual ICollection<Business> Businesses { get; set; }
}
I then have the following method to return a Single Business Instance:
public Business GetBusinessForUser(string userId)
{
using (var db = new MyContext(_connectionString))
{
var q =
from b in db.Businesses
join bm in db.BusinessMembers on b.ID equals bm.ID_Business
where bm.UserId == userId
select b;
return q.FirstOrDefault();
}
}
Problem I'm having is I want to 'Include' the BusinessStatus for that single Business entity and don't know how to do this.
I need to be able to do:
Business businessEntity = _dataServices.GetBusinessForUser(userId);
if (businessEntity.BusinessStatus.Code == "ACT")
{
// Whatever
}
First, add this to the list of usings
using System.Data.Entity;
Then you can use the .Include() method to load additional children in your query
public Business GetBusinessForUser(string userId)
{
using (var db = new MyContext(_connectionString))
{
var q =
(from b in db.Businesses
join bm in db.BusinessMembers on b.ID equals bm.ID_Business
where bm.UserId == userId
select b).Include(business => business.BusinessStatus);
return q.FirstOrDefault();
}
}
I would also avoid using the join method explicitly. If your model has correct relationships (e.g. foreign keys), you should be able to just do this:
var q = db.Businesses
.Where(b => b.BusinessMembers.Any(bm => bm.UserId == userId))
.Include(b => b.BusinessStatus);
return q.FirstOrDefault();
or even
var q = db.BusinessMembers
.Where(bm => bm.UserId == userId)
.Select(bm => bm.Business)
.Include(b => b.BusinessStatus);

Categories

Resources