Entity Framework : join two tables and where clause - c#

I'm having trouble working with Entity Framework and PostgreSQL, does anybody know how to join two tables and use the second table as a where clause?
The select I want to do in Entity Framework would be in SQL:
SELECT ai.id, ai.title, ai.description, ai.coverimageurl
FROM app_information ai
INNER JOIN app_languages al on al.id = ai.languageid
WHERE al.languagecode = 'es'
Currently I have this
appInformationToReturn = context.app_information
.Join(context.app_language, ai => ai.languageid,
al => al.id, (ai, al) => new AppInformation()
{
id = ai.id,
title = ai.title,
description = ai.description,
coverimageurl = ai.coverimageurl
})
.Where()
.FirstOrDefault();
I don't know how to build the where clause.

Like this:
appInformationToReturn = context.app_information
.Join(context.app_language, ai => ai.languageid,
al => al.id, (ai, al) => new
{
id = ai.id,
title = ai.title,
description = ai.description,
coverimageurl = ai.coverimageurl,
lang = al.languagecode
}).Where(x=>x.lang == "es")
.Select(x=> new AppInformation()
{
id = x.id,
title = x.title,
description = x.description,
coverimageurl = x.coverimageurl
})
.FirstOrDefault();

try this:
var item = (
from ai in context.app_information
join al in context.app_language on ai.languageid equals al.id
where (al.languagecode == "es")
select new AppInformation
{
id = ai.id,
title = ai.title,
description = ai.description,
coverimageurl = ai.coverimageurl
}).FirstOrDefault();
or try shorter
var item = context.app_information
.Where(ai => ai.app_language.languagecode == "es")
.Select(ai => new AppInformation
{
id = ai.id,
title = ai.title,
description = ai.description,
coverimageurl = ai.coverimageurl
})
.FirstOrDefault();

Related

How can I get a list of objects related to a min from a Linq

I have a Linq Query that is working as intended, but I need to add the code so that it will show me ONLY the people with the less cases assigned for an app that is been used to treat customers inquiries. The idea behind the query is so that it will let me automatically assign inquiries randomly between those agents which have less assigned issues to cover.
As a simple example, lets say I have 5 agents with just 1 case each, I need to randomly assign one of them to an Inquire which has currently no agent assigned. So all I'm looking for is a way to actually get all the agents with the smallest number of cases assigned.
So far this is the full proof of concept code:
var inquires = new List<Inquire>();
var agents = new List<Agent>();
LoadData();
var assignationsPerAgent = (from agent in agents
join inq in inquires on agent equals inq.AssignedAgent into agentsInInquires
select new {
o_agent = agent,
casesAssignedTo = agentsInInquires.Count()
}).ToList();
//This works but is NOT the kind of solution I'm looking for
var min = assignationsPerAgent.Min(c => c.casesAsignedTo);
var agentWithMin = assignationsPerAgent.Where(a => a.casesAsignedTo == min);
Console.WriteLine();
void LoadData()
{
agents = new(){
new Agent{ Id = Guid.Parse("317d3d26-25c2-49da-aa4b-b7e49a1b9015"), Name = "Robert" },
new Agent{ Id = Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"), Name = "Corina" },
new Agent{ Id = Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"), Name = "John" },
new Agent{ Id = Guid.Parse("34e091e4-cc7a-4222-9885-5de5bb5a0291"), Name = "Jack"},
new Agent{ Id = Guid.Parse("f22dcb4e-e927-4ddf-ae66-f37c0de6753d"), Name = "Samuel"}
};
inquires = new(){
new Inquire{ CustomerName = "Paula", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("317d3d26-25c2-49da-aa4b-b7e49a1b9015"))},
new Inquire{ CustomerName = "Barry", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"))},
new Inquire{ CustomerName = "Bertie", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"))},
new Inquire{ CustomerName = "Herman", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"))},
new Inquire{ CustomerName = "Ashley", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("317d3d26-25c2-49da-aa4b-b7e49a1b9015"))},
new Inquire{ CustomerName = "Tate", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"))},
new Inquire{ CustomerName = "Bonnie", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"))},
new Inquire{ CustomerName = "Tabitha", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("90ca6658-95d4-4df4-a072-159087feddc0"))},
new Inquire{ CustomerName = "Ashley", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("34e091e4-cc7a-4222-9885-5de5bb5a0291"))},
new Inquire{ CustomerName = "Josie", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"))},
new Inquire{ CustomerName = "Kelly", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("84188e21-8147-498f-bc2a-59874dc4a24a"))},
new Inquire{ CustomerName = "Kelly", AsignedAgent = agents.Single(a => a.Id == Guid.Parse("f22dcb4e-e927-4ddf-ae66-f37c0de6753d"))},
};
}
#nullable disable
class Inquire
{
private Guid _id;
public Guid Id
{
get
{
return _id;
}
private set
{
_id = Guid.NewGuid();
}
}
public string CustomerName { get; set; }
public Agent AsignedAgent { get; set; }
}
#nullable disable
class Agent
{
public Guid Id {get; set;}
public string Name { get; set; }
}
Please take in consideration that the assignationsPerAgent variable is simulating data coming from a query in the database (The actual query is below). If the "easy" way to do this comes from the SQL that it's also an acceptable solution.
SELECT u.Id, COUNT(g.Id) as QtyAsig
FROM Users as u
LEFT JOIN GeneralInquires AS g ON u.Id = g.UserId
GROUP BY u.Id
ORDER BY COUNT(g.Id)
What I'm getting from this Query is:
Id QtyAsig
8A21A6D2-0CEC-4F5C-2A6B-08DA60967E94 1
323C8D1A-2FAE-4ECC-D7A2-08DA6098F19A 1
BA485F3C-C44A-4FE5-9BFA-08DA64EF283A 1
8F0E856E-FA0B-4167-BBEF-08DA6451FA81 2
40952727-5C76-4902-9C4F-08DA638B3068 3
DD51085A-5BE3-4872-F4B5-08DA6E7828AA 4
What I need is:
Id QtyAsig
8A21A6D2-0CEC-4F5C-2A6B-08DA60967E94 1
323C8D1A-2FAE-4ECC-D7A2-08DA6098F19A 1
BA485F3C-C44A-4FE5-9BFA-08DA64EF283A 1
Thank you in advance!
check this
var assignationsPerAgent = (from agent in agents
join inq in inquires on agent equals inq.AsignedAgent into agentsInInquires
from inq in agentsInInquires.DefaultIfEmpty()
select new
{
o_agent = agent,
casesAssignedTo = agentsInInquires.Count()
}).GroupBy(x=>x.casesAssignedTo).OrderBy(x=>x.Key).FirstOrDefault();
Linq doesn't require one statement and splitting results has no impact on performance. Try following :
List<Inquire> sortedInquires = inquires.OrderBy(x => x.AsignedAgent.Id).ToList();
var results = (from a in agents
//join i in sortedInquires on a.Id equals i.Id
join i in sortedInquires on a.Id equals i.AssignedAgent
select new { agent = a, inquires = i}
).GroupBy(x => x.agent.Id)
.Select(x => x.First())
.ToList();

Linq Lambda Error : The specified LINQ expression contains references to queries that are associated with different contexts

I receive this error, and I tried a lot to solve it, but I receive other errors, is there a solution?
using (var contextDb1 = new Db1Context(System.Web.HttpContext.Current.Session["DB1ConnectionString"].ToString(), false))
{
using (var contextDb2 = new Db2Context(System.Web.HttpContext.Current.Session["DB2ConnectionString"].ToString(), false))
{
var messagesList = contextDb2.Messages
.Select(m => new MessagesViewModel
{
UserName = contextDb1.UsersInfo.FirstOrDefault(u=>u.Id == m.UserId).UserName,
MessageId = m.MessageId,
MessageText = m.MessageText,
DateTime = m.DateTime
})
.ToList();
return messagesList;
}
}
You cannot query two different databases via the same LINQ Query. But you can use intermediate result to execute two queries to databases and then combine result.
using (var contextDb1 = new Db1Context(System.Web.HttpContext.Current.Session["DB1ConnectionString"].ToString(), false))
using (var contextDb2 = new Db2Context(System.Web.HttpContext.Current.Session["DB2ConnectionString"].ToString(), false))
{
var rawMessages = contextDb2.Messages
.Select(m => new
{
m.UserId
m.MessageId,
m.MessageText,
m.DateTime
})
.ToList();
var userIds = rawMessages.Select(x => xu.UserId);
var usersInfo = contextDb1.UsersInfo.Where(u => userIds.Contains(u.Id))
.Select(u => new
{
UserId = u.Id,
UserName = u.UserName
});
var messageQuery =
from m in rawMessages
join u in usersInfo.AsEnumerable() on m.UserId equals u.UserId into gj
from u in gj.DefaultIfEmpty()
select new MessagesViewModel
{
UserName = u?.UserName,
MessageId = m.MessageId,
MessageText = m.MessageText,
DateTime = m.DateTime
};
var messagesList = messageQuery.ToList();
return messagesList;
}

Return children and subchildren withouth having sub-array Linq

I have a linq query that returns users/employees with their corresponding supervisors.
List<OrgChartViewModel> OrgChart = new List<OrgChartViewModel>();
var userlist = (from u in users
select new OrgChartViewModel
{
id = u?.id.ToString(),
pid = u?.pid.ToString(),
name = u?.name,
title = u?.title,
img = u?.img
}).OrderBy(x => x.name).ToList();
OrgChart.AddRange(userlist);
return Json(OrgChart.DistinctBy(x => x.id));
However, I need a query that returns the supervisor and their children along with their sub-children without having a sub-array/nested array.
What I have tried :
List<OrgChartViewModel> OrgChart = new List<OrgChartViewModel>();
var userlist = (from u in users
select new OrgChartViewModel
{
id = u?.id.ToString(),
pid = u?.pid.ToString(),
name = u?.name,
title = u?.title,
img = u?.img
}).OrderBy(x => x.name).ToList();
OrgChart.AddRange(userlist);
foreach (var ul in userlist)
{
var userlist2 = (from u in users
select new OrgChartViewModel
{
id = u?.id.ToString(),
pid = u?.pid.ToString(),
name = u?.name,
title = u?.title,
img = u?.img
}).Where(x => x.pid == ul.id).OrderBy(x => x.name).ToList();
OrgChart.AddRange(userlist2);
}
return Json(OrgChart.DistinctBy(x => x.id));
But this only returns the first layer of sub-children. What I want to achieve is to return unlimited layers of sub-children without having sub-arrays.

Select List of Object Which Contain Another List by LINQ

I have three database model which are shown below
I have two DTO class which are shown below
class RoleDTO
{
string RoleId;
string EnglishName;
Guid TypeId;
List<ClaimDTO> claims;
}
class ClaimDTO
{
string ActionID;
string ActionCode;
string ActionLevel;
string GrantDate;
}
Now I want to retrieve List of RoleDTO object from the database. So far I tried
public List<RoleDTO> GetRoleByType(Guid roleTypeId)
{
var roleDTOs = (from r in ctx.Roles
join rc in ctx.RoleClaims on r.RoleID equals rc.RoleID
join a in ctx.Actions on rc.ActionID equals a.ActionID
where r.RoleTypeID == roleTypeId
select new RoleDTO
{
RoleId = r.RoleID,
EnglishName = r.EnglishName,
TypeId = r.TypeID,
claims = List of ClaimDTO objects related to this role
}).ToList();
return roleDTOs;
}
My question is how can I retrieve list of ClaimDTO objects inside select statement. Is my linq correct?
I am using Telerik OpenAccess as ORM.
Below change should help to get the results
public List<RoleDTO> GetRoleByType(Guid roleTypeId)
{
var roleDTOs = (from r in ctx.Roles
join rc in ctx.RoleClaims on r.RoleID equals rc.RoleID
where r.RoleTypeID == roleTypeId
select new RoleDTO
{
RoleId = r.RoleID,
EnglishName = r.EnglishName,
TypeId = r.TypeID,
claims = ctx.Actions.Where( c => c.ActionId == rc.ActionId).Select( s => new ClaimDTO
{
ActionID = s.ActionID,
ActionCode = s.ActionCode,
ActionLevel = s.ActionLevel,
GrantDate = s.GrantDate
})ToList()
}).ToList();
return roleDTOs;
}
Another Alternative
List<ClaimDTO> claimsList = ctx.Actions.Select( s => new ClaimDTO
{
ActionID = s.ActionID,
ActionCode = s.ActionCode,
ActionLevel = s.ActionLevel,
GrantDate = s.GrantDate
})ToList();
var roleDTOs = ctx.Roles.Join(ctx.RoleClaims, r => r.RoleID, rc => rc.RoleID, (r,rc) => new
{
r,rc
}).Where( r => r.RoleTypeID == roleTypeId)
.Select( row => new RoleDTO
{
RoleID = row.r.RoleID,
EnglishName = row.r.EnglishName,
TypeID = row.r.TypeID,
claims = claimsList.Where( c => c.ActionId == rc.ActionId)
}).ToList();
If you use Include method then below query could help
var roleDTOs = ctx.Roles.Include("RoleClaims").Join(ctx.Actions, r => r.RoleClaims.Select(rc => rc.ActionID).FirstOrDefault() , a => a.actionid , (r,a) => new
{
r,a
}.Where(r => r.RoleTypeID == roleTypeId)
.Select( row => new RoleDTO
{
RoleID = row.r.RoleID,
EnglishName = row.r.EnglishName,
TypeId = row.r.RoleTypeID,
Claims = row.a.Select( c => new ClaimDTO
{
ActionID = c.ActionID,
ActionCode = c.ActionCode,
ActionLevel = c.ActionLabel,
GrantDate = row.r.RoleClaims.Select( g => g.grantDate)
})
}).ToList();

Cross Context LINQ Joins in Azure?

We're currently migrating our production platform to Azure, and as such I need to move over all of our support tools. Previously, we relied heavily on data adapters and stored procedures, and many of these stored procedures performed cross-database joins.
With our migration to Azure, none of these cross-database joins are operational. I tried moving our data adapters to Entity Framework, but I cannot seem to make them work. Instead, I get an error stating that cross-context joins are not allowed. Many of these queries rely on data from multiple databases, so I'm just trying to figure out what the best method of approach is to get this operational.
I've looked at several of the other questions asking for similar solutions, but none of them seem terribly applicable to my solution.
For example, here's one of the more simple queries in SQL:
USE CustomerDB1234
SELECT DISTINCT u.[UserID]
,u.[UserLogin]
,u.[UserPhoneNumber]
,u.[UserPasswordHash]
, ISNULL(gl.[gl_login_name],'* no global login ID') AS [gl_login_name]
,gl.[gl_password_hash]
,gl.[gl_GUID]
,gl.[gl_Email_Validated]
,u.[usr_unit_set_id]
,oob.[oob_org_id]
FROM [dbo].[User] u WITH (NOLOCK)
LEFT JOIN [dbo].[OrganizationObjectBridge] oob WITH (NOLOCK) ON oob.[oob_object_type_id] = 9 AND oob.[oob_object_id]= u.UserID
LEFT JOIN [MainServer].[MainDb].[dbo].[GlobalLoginCustomerBridge] glcb WITH (NOLOCK) ON glcb.[glcbr_user_id] = u.UserID
AND glcb.[glcbr_customer_id] = dbo.efnGetCustomerID()
LEFT JOIN [MainServer].[MainDb].[dbo].[GlobalLogin] gl WITH (NOLOCK) ON gl.[gl_id] = glcb.[glcbr_gl_id]
WHERE ([UserID] = #userID OR #userID IS NULL)
AND ([UserDisabled] = #isDisabled OR #isDisabled IS NULL)
ORDER BY [gl_login_name]
And in Linq, it would look similar to:
List<User2> userList = new List<User2>();
using (var e = new eContext())
using (var context = new CustomerContext(CustomerID))
{
var databaseConnections = e.DatabaseConnectionStrings;
var customer = e.Customers.Select(n => new
{
ID = n.CustomerID,
Name = n.CustomerName,
Email = n.CustomerEmail,
Website = n.CustomerWWW,
Logo = n.CustomerLogo,
DatabaseConnectionName = databaseConnections.FirstOrDefault(d => d.DatabaseConnectionID == n.DatabaseConnectionID).DatabaseConnectionName,
DatabaseConnectionString = databaseConnections.FirstOrDefault(d => d.DatabaseConnectionID == n.DatabaseConnectionID).DatabaseConnectionString1,
AccountNumber = n.CustomerAcctNumber
}).FirstOrDefault(n => n.ID == CustomerID);
userList = context.Users
.Join(e.GlobalLoginCustomerBridges,
u => u.UserID,
glcb => glcb.glcbr_user_id,
(u, glcb) => new { u, glcb })
.Where(n => n.glcb.glcbr_customer_id == CustomerID)
.Join(e.GlobalLogins,
glcb => glcb.glcb.glcbr_gl_id,
gl => gl.gl_id,
(glcb, gl) => new { glcb, gl })
.Join(context.OrganizationObjectBridges,
glcb => glcb.glcb.u.UserID,
oob => oob.oob_object_id,
(glcb,oob) => new {glcb, oob})
.Where(n=>n.oob.oob_object_type_id == 9)
.Select(n => new
{
ID = n.glcb.glcb.u.UserID,
GlobalLogin = n.glcb.gl.gl_login_name,
FirstName = n.glcb.glcb.u.UserFirstName,
MiddleName = n.glcb.glcb.u.UserMiddleName,
LastName = n.glcb.glcb.u.UserLastName,
GUID = n.glcb.gl.gl_GUID,
UserID = n.glcb.gl.gl_id,
HasSHA256Hash = n.glcb.gl.gl_password_hash_sha256 == null,
Customer = customer,
Organization = context.Organizations
.Select(o => new
{
ID = o.org_id,
Name = o.org_name,
ParentID = o.org_parent_id,
ExternalID = o.org_external_id,
Default = o.org_default,
Logo = o.org_logo,
URL = o.org_url,
PeerGroupID = o.org_peer_grp_id,
ExternalInfo = o.org_external_info
}).Cast<Organization2>().FirstOrDefault(o=>o.ID == n.oob.oob_org_id)
}).Cast<User2>().ToList();
}
Two approaches:
Perform the joins in the application in memory. Depending on the query this is more or less efficient. Also, the code changes required range from tiny to terrible.
Merge databases together. Having many databases without a physical reason for that is an anti-pattern. Databases are not logical units of application modularization. Document modularization through schemas or table name prefixes. Databases are physical units of deployment.
Third approach: Run a SQL Server in a VM.
By using the information posted by the other answer, I came up with a solution that appears to work. Granted, it doesn't appear nearly as efficient or as concise as cross-database joins, but it gets the job done.
using (var context = new CustomerContext(CustomerID))
using (var e = new eContext())
{
var globalUserList = e.GlobalLoginCustomerBridges
.Join(e.GlobalLogins,
glcb => glcb.glcbr_gl_id,
gl => gl.gl_id,
(glcb, gl) => new { glcb, gl })
.Where(n => n.glcb.glcbr_customer_id == CustomerID)
.Select(n => new User2
{
ID = (int)n.glcb.glcbr_user_id,
GlobalLogin = n.gl.gl_login_name,
GUID = n.gl.gl_GUID
}).ToList();
var customer = e.Customers
.Join(e.DatabaseConnectionStrings,
c => c.DatabaseConnectionID,
d => d.DatabaseConnectionID,
(c, d) => new { c, d })
.Select(n => new Customer2
{
ID = n.c.CustomerID,
Name = n.c.CustomerName,
DatabaseConnectionName = n.d.DatabaseConnectionName,
DatabaseConnectionString = n.d.DatabaseConnectionString1,
GUID = n.c.cust_guid,
}).ToList().FirstOrDefault(n => n.ID == CustomerID);
var orgs = context.Organizations
.Select(o => new Organization2
{
ID = o.org_id,
Name = o.org_name,
}).ToList();
var users = context.Users
.Select(n => new User2
{
ID = n.UserID,
FirstName = n.UserFirstName,
}).ToList();
var userList = users
.Join(globalUserList,
u => u.ID,
gl => gl.ID,
(u, gl) => new { u, gl })
.Join(context.OrganizationObjectBridges,
u => u.u.ID,
oob => oob.oob_object_id,
(u, oob) => new { u, oob })
.Where(o => o.oob.oob_object_type_id == 9)
.Select(n => new User2
{
ID = n.u.u.ID,
GlobalLogin = n.u.gl.GlobalLogin,
FirstName = n.u.u.FirstName,
GUID = n.u.gl.GUID,
Customer = customer,
Organization = orgs.FirstOrDefault(o => o.ID == n.oob.oob_org_id)
}).Where(n => !isDisabled != null && n.Disabled == isDisabled).ToList();
return userList;
}

Categories