.NET Core - join 2 tables with AsQueryable - entity-framework

I have two nested classes: Partner contains a Company (that has a field "Name")
I do a search by Id on the partner's Id
I want to do a search on the company's "Name" field
here is my poco:
public class Partner
{
[Required]
public int? Id { get; set; }
[Required]
public Company Company { get; set; }
using AsQueryable, I can then stack filters one by one
I try to have a query that joins the second table to do a search on that entity's name field
public DbSet<Partner> Partners { get; set; }
...
var data = _context.Partners.AsQueryable();
if (partnersSearch.SearchById != null)
{
data = data.Where(p => p.Id == partnersSearch.SearchById.GetValueOrDefault());
}
if (partnersSearch.SearchByName != null)
{
data = data.Include(a => a.Company.Select(b => b.Name = partnersSearch.SearchByName));
but for the join between the tables, the last line cannot compile
it complains that Company does not contain a definition of has no Select
what am I doing wrong ?
thanks for helping me on this

If you try a where after your include. Does that help?
data.Include(a => a.Company).Where(partner=>partner.Company.Name.equals(partnersSearch.SearchByName))

Related

Linq query to join three tables and return a object along with a list of another object in Entity Framework Core

I have three tables, Organization, Department, and OrganizationDepartments. here is the relationship between them.
Now I would like to join these three tables and create another object for a DTO class. This DTO object has some properties and a list of other DTOs. Here is the DTO Class.
Organization DTO:
public class OrganizationDto
{
public string Id { get; set; }
public string OrganizationName { get; set; }
public string Logo { get; set; }
public bool? IsActive { get; set; }
public IList<OrganizationDepartmentDto> OrganizationDepartments { get; set; }
}
OrganizationDepartment DTO:
public class OrganizationDepartmentDto
{
public string OrganizationId { get; set; }
public string OrganizationName { get; set; }
public string DepartmentId { get; set; }
public string DepartmentName { get; set; }
}
Now I would like to write a LINQ query to get a Organization object along with all the departments related to that organization. The query is imcomplete because I don't know how can I get all the department information as list in a single query. The code is below:
var organizationInfo = (from org in _dbContext.Organizations
join orgDept in _dbContext.OrganizationDepartments on org.Id equals orgDept.OrganizationId
join dept in _dbContext.Departments on orgDept.DepartmentId equals dept.Id
where org.Id.ToUpper() == id.ToUpper()
orderby org.CreatedOn ascending
select new OrganizationDto
{
Id = org.Id,
OrganizationName = org.OrganizationName,
Logo = org.Logo,
IsActive = org.IsActive,
OrganizationDepartments = //TODO:..
}
);
Can anyone help me to get the department lists of that organization's object (see the TODO:)?
If your entities are mapped correctly, and the relationships are correctly configured.
you can use .Include("OrganizationDepartment") and .ThenInclude("Department")to ensure relations are included into the generated Query.
If you insist on using Query Syntax. e.g from org in context.Organization
you can write out the query like this.
var q = (from org in _dbContext.Organizations
where org.Id.ToUpper() == id.ToUpper()
orderby org.CreatedOn ascending
select new OrganizationDto
{
Id = org.Id,
OrganizationName = org.OrganizationName,
Logo = org.Logo,
IsActive = org.IsActive,
OrganizationDepartments = org.OrganizationDepartments.ToList()
}
Depending on your usecase. Sometimes you are not interested in actually showing the "many to many" table outside of the scope of your database.
so it might make more sense to actually flatten the Dto.
that query would look like
var q = (from org in _dbContext.Organizations
where org.Id.ToUpper() == id.ToUpper()
orderby org.CreatedOn ascending
select new OrganizationDto
{
Id = org.Id,
OrganizationName = org.OrganizationName,
Logo = org.Logo,
IsActive = org.IsActive,
Departments= org.OrganizationDepartments.Select(t => t.Departments).ToList()
}

How to handle null value in Auto-mapper ProjectTo

I am working on .NET Core application with Entity Framework core 2.1 and auto-mapper 3.2. In my following script, I am getting null value and get an error when I am trying to ProjectTo(myviewClass). Now I know I can check individual value in following script by do userRoleList.select(x=>x.ConsultationId) == null? null: projectTo but the issue is, its collection so how do I apply similar logic as you can see I am getting a collection of consultation records where its ConsultationId contains in userRoleLits.
LINQ
(from user in Context.Users
join userRole in Context.UserRoles on user.Id equals userRole.UserId into userRoleList
where (user.Id == (UserId ?? user.Id))
select new UsersWithAccessProfileDataView
{
UserId = user.Id,
UserName = user.Name,
Consultation = Context.Consultations.Where(x => userRoleList.Select(y => y.ConsultationId).Contains(x.Id)).ProjectTo<ConsultationDataView>() //need help here
}).OrderBy(x => x.UserName);
model view class
public class UsersWithAccessProfileDataView
{
public Guid UserId { get; set; }
public string UserName { get; set; }
public IQueryable<ConsultationDataView> Consultation { get; set; }
}

Child List Element Gets Only 1 Record in Entity Framework

In Entity Framework, I would like to get one object which includes a list, but list gets only first record.
I have 2 objects Sale and Profile, they are different from database objects, I create these objects in query like "select new Sale { }". Profile object contains Sale type list. When query executed, list gets just first record in database.
Sale Complex Object
public class Sale
{
public int Id { get; set; }
public string Header { get; set; }
public double Price { get; set; }
}
Profile Complex Object
public class Profile
{
public int Id { get; set; }
public string Name { get; set; }
public List<Sale> SalesList { get; set; }
}
I use left join because it should insert this object to list, if next object is null.
Query Here
Profile profile = (from u in db.USER
join s in db.SALE on u.ID equals s.USER_ID into saleleft
from salej in saleleft.DefaultIfEmpty()
where u.ID == _userId
select new Profile
{
Id = u.ID,
Name = u.NAME,
SalesList= new List<Sale>()
{
salej != null ? new Sale
{
Id=postj.ID,
Header=salej.HEADER,
Price=salej.PRICE
} : null
}.ToList()
}).FirstOrDefault();
I guess this can be about FirstOrDefault() method. Hence I think it should get all records to SalesList. How can I get all records to list? Any idea?
Thanks in advance.
I think you need to use group here. Could you try this and let me know if it works?
// didn't test the code
Profile profile = (from u in db.USER
join s in db.SALE on u.ID equals s.USER_ID into saleleft
where u.ID == _userId
from salej in saleleft.DefaultIfEmpty()
group salej by new { u.ID, u.NAME } into g
select new Profile
{
Id = g.Key.ID,
Name = g.Key.NAME,
SalesList = g.Select( x => new Sale { Id = postj.ID, Header = x.HEADER, Price = x.PRICE }).ToList()
}).FirstOrDefault();
Btw, what is postj?

Self referencing (1:1) a table in Entity Framework code first model

I'm trying to self reference a table in my model to get a couple of details for my User entity
I have a class that looks like:
public class User
{
[Key]
[Column("recid")]
public int Id { get; set; }
[Column("givenname")]
public string FirstName { get; set; }
[Column("sn")]
public string LastName { get; set; }
[Column("mail")]
public string Email { get; set; }
[Column("managerEmail")]
public string LineManagerEmail { get; set; }
public string LineManagerFirstName { get; set; }
public string LineManagerLastName { get; set; }
}
How can I map this so that when returning a User the LineManagerFirstName and LineManagerLastName is retrieved from the same table, joined on LineManagerEmail?
for example, I anticipate the SQL to be something like:
SELECT
user.recid,
user.givenName,
user.sn,
user.mail,
user.managerEmail,
manager.givenName as lineManagerFirstName,
manager.givenName as lineManagerLastName,
FROM user
INNER JOIN user AS manager
ON user.managerEmail = manager.mail
In my Context class, I know I'll need to override the OnModelCreating method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().
}
...but being new to EF, this is where I'm getting a bit stuck!
If you use a view, you will probably not be able to update users as a view is readonly.
You should create entities according to tables and then query according to your needs and materialize a UserExtended with a query like
var q = from
u in Users
select
new UserExtended {
Id = u.Id,
/* .... */
LineManagerFirstName = u.Manager.FirstName
/* .... */
}
or a more elaborated query, in case of self join without the PK.
var q =
from u in Users
join m in Users on u.Email equals m.Email
select
new UserExtended {
Id = u.Id,
/* .... */
LineManagerFirstName = m.FirstName
/* .... */
}
will give you the following SQL (fields name do not match as I use one of my schema)
SELECT
[Extent1].[idUtilisateur] AS [idUtilisateur],
[Extent2].[Email] AS [Email]
FROM [dbo].[tableU] AS [Extent1]
INNER JOIN [dbo].[tableU] AS [Extent2] ON
([Extent1].[Email] = [Extent2].[Email])
OR (([Extent1].[Email] IS NULL) AND ([Extent2].[Email] IS NULL))

EF Many To Many Join - Lazy Loading Disabled

Here is my scenario:
public class Contact
{
public Guid ContactId { get; set; }
........
public Guid WorkspaceId { get; set; }
public Workspace Workspace { get; set; }
}
public class Workspace
{
public Guid WorkspaceId { get; set; }
........
public ICollection<Contact> ReferencedContacts { get; set; }
public ICollection<Contact> OwnedContacts { get; set; }
}
The logic is the following one: A contact can't exists outside a workspace (means that the workspace owns the contact).
A user has a workspace, and it places the 'owned contacts' in it (owned contact = the contact information describes the users such as profession, name, address, etc).
Also a user workspace can hold a reference to contacts owned by other users (here comes the join table which stores the relation between a workspace and the referenced contacts).
public WorkspaceMap()
{
....
HasMany(w => w.ReferencedContacts).WithMany().Map(mp =>
{
mp.ToTable("WorkspaceReferencedContacts");
mp.MapLeftKey("WorkspaceId");
mp.MapRightKey("ContactId");
});
}
public ContactMap()
{
......
HasRequired(c => c.Workspace).WithMany(w => w.OwnedContacts).HasForeignKey(c => c.WorkspaceId).WillCascadeOnDelete(false);
Property(c => c.WorkspaceId).HasColumnName("WorkpaceId");
}
What I am trying to do is to get all referenced contacts for a specific workspace using query methods. The SQL version of the query would be the following one:
SELECT * FROM dbo.Contacts c
INNER JOIN dbo.WorkspaceReferencedContacts wc ON wc.ContactId = c.ContactId
WHERE wc.WorkspaceId = '57F685C0-428C-44C3-8708-F30B5AF34CAE';
I have approached many ways without any success. Please note that lazy loading is disabled (there is no point to discuss why...).
...get all referenced contacts for a specific workspace...
I think:
var contacts = context.Workspaces
.Where(w => w.WorkspaceId == "57F685C0-428C-44C3-8708-F30B5AF34CAE")
.Select(w => w.ReferencedContacts)
.SingleOrDefault();