How to query with a join with linq to sql - c#

I'm trying to query for gifts given a term from my categories table. Entity Framework created a bridge table to connect my "Gift" with my "GiftCategroies". But the query I have yielded no results.
From DbContext:
public DbSet<Gift> Gifts { get; set; }
public DbSet<GiftCategory> Categories { get; set; }
The two entities I created:
public class Gift
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<GiftCategory> Categories { get; set; }
public int Rating { get; set; }
}
public class GiftCategory
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Gift> Gifts { get; set; }
}
Here is my query to try and fetch the gifts given a giftcategory term. No results returned. I'm not sure if I even need a join for this type of query.
var model =
from gifts in db.Gifts
join giftCategory in db.Categories on gifts.Id equals giftCategory.Id
where giftCategory.Name.Contains(searchTerm)
select gifts;

You should use navigation properties instead of joins:
var gifts = (from c in db.Categories
from g in c.Gifts
where c.Name.Contains(searchTerm)
select g).Distinct().ToList();

Related

SQL expression working with many-to-many to LINQ

ASP CORE MVC application.
I have 2 tables:
public class StudentModel
{
public Guid Id { get; set; }
public string ChineseName { get; set; }
public string EnglishName { get; set; }
public DateTime BirthdayDate { get; set; }
public List<StudentParent> StudentParent { get; set; }
public List<StudentCourse> StudentCourse { get; set; }
public StudentModel()
{
StudentParent = new List<StudentParent>();
StudentCourse = new List<StudentCourse>();
}
}
public class ParentModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string PhoneNumber { get; set; }
public List<StudentParent> StudentParent { get; set; }
public ParentModel()
{
StudentParent = new List<StudentParent>();
}
}
With relation many-to-many.
public class StudentParent
{
public Guid StudentId { get; set; }
public StudentModel Student { get; set; }
public Guid ParentId { get; set; }
public ParentModel Parent { get; set; }
}
The question is: How to get Id from ParentModel table if I know student Id?
In Microsoft SQL Server Management Studio I can execute this command and get what I want:
SELECT ParentModels.Id
FROM StudentModels
LEFT OUTER JOIN StudentParent
ON StudentModels.Id = StudentParent.StudentId
LEFT OUTER JOIN ParentModels
ON StudentParent.ParentId = ParentModels.Id
WHERE StudentModels.Id = 'A1F38C12-AE65-464C-C489-08D814F4CDDC'
How to write this code in Visual Studio with LINQ?
I tried this instead:
Guid parentID = context.StudentModels.FromSqlRaw("SELECT ParentModels.Id FROM StudentModels LEFT OUTER JOIN StudentParent ON StudentModels.Id = StudentParent.StudentId LEFT OUTER JOIN ParentModels ON StudentParent.ParentId = ParentModels.Id WHERE StudentModels.Id = '{0}'", guid).FirstOrDefault();
But it doesn't work.
With this being many-to-many, there could be more than 1 ParentModel.Id for each student.
This being said, you could find them like this:
IEnumerable<Guid> parentIds = context.ParentModels
.Where(p => p.StudentParent
.Any(sp => sp.Student.Id == new Guid("A1F38C12-AE65-464C-C489-08D814F4CDDC")))
.Select(p => p.Id);
In such complex query where you need to make a lot of joins most developers prefer query LINQ syntax. It seems to be easier to read and understand.
IEnumerable<Guid> parentIds =
(from sm in context.StudentModels
join sp in context.StudentParent on sm.Id equals sp.StudentId
join pm in context.ParantModels on sp.ParentId equals pm.Id
where sm.Id == new Guid("A1F38C12-AE65-464C-C489-08D814F4CDDC")
select pm.Id).ToList();
More info about query and method syntax you can find in Miscrosoft Docs

C# LINQ query with joins and multiple counts

I need to translate this SQL-query to Linq-Entity query
SELECT Company.name, COUNT(DISTINCT User.id), COUNT(DISTINCT Office.id)
FROM Company
INNER JOIN Office ON Company.id = Office.companyId
INNER JOIN Employee ON Office.id = Employee.officeId
GROUP BY Company.name
So I want a result that gives me a name of the company, count of unique employees and count of offices in a single row.
I have these entities
public class Company
{
public int id { get; set; }
public string name { get; set; }
public List<Office> offices { get; set; }
}
public class Office
{
public int id { get; set; }
public string name { get; set; }
public int companyId { get; set; }
public List<Employee> employees { get; set; }
}
public class Employee
{
public int id { get; set; }
public string name { get; set; }
public int officeId { get; set; }
}
and ViewModel:
public class MyViewModel
{
public Company company { get; set; }
public int employeeCount { get; set; }
public int officeCount { get; set; }
}
What I have been trying in my controller:
var viewModel =
from c in _context.Companies
join o in _context.Offices on c.id equals o.companyId
join e in _context.Employees on o.id equals e.officeId
select new MyViewModel { company = c, employeeCount = ??, officeCount =
??}
return View(viewModel);
So I don't know how the count() and group by are working.
First, LINQ has no direct equivalent of the SQL COUNT(DISTINCT expr) construct.
Second and more important, in LINQ to Entities you don't need to follow the SQL rules. We don't use joins, but navigation properties, and basically write the query like if we are working with objects, and let EF translate it to SQL.
The LINQ to Entities query in question is natural and simple as that:
var query = _context.Companies
.Select(c => new MyViewModel
{
company = c,
officeCount = c.offices.Count(),
employeeCount = c.offices.Sum(o => o.employees.Count()),
});

select specific field in each joined table in LINQ sql query entity framework

public class OnLoginData
{
public List<TableDetails> lstTableDetails { get; set; }
public List<CategoryDetails> lstCategoryDetails { get; set; }
}
public class TableDetails
{
public int TableId { get; set; }
public int TableNumber { get; set; }
public string TableName { get; set; }
}
public partial class CategoryDetails
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public long? SystemId { get; set; }
public int? SortId { get; set; }
}
var queryLoginAdimin = from admin in conDb.SystemAdminMasters
join system in conDb.SystemMasters on admin.SystemID equals system.SystemId into SM
join category in conDb.MenuCategoryMasters on admin.SystemID equals category.SystemId into CM
join menu in conDb.MenuMasters on admin.SystemID equals menu.SystemId into MM
join table in conDb.TableMasters on admin.SystemID equals table.SystemId into TM
select new OnLoginData
{
lstTableDetails = TM.Select(o => new
{
o.TableId,
o.TableName,
o.TableNumber
}).ToList()
};
Please check the above code, I'm trying to do joins using multiple tables and I don't require all fields from database tables. I only need those fields where I have take a separate class TableDetails and CategoryDetails. I want to select those fields from above linq query and create a whole List that is On LoginData.
How do I do that?
You Can Query in Below Way
var queryLoginAdimin =
from admin in conDb.SystemAdminMasters
join system in conDb.SystemMasters on admin.SystemID equals system.SystemId into SM
join category in conDb.MenuCategoryMasters on admin.SystemID equals category.SystemId into CM
join menu in conDb.MenuMasters on admin.SystemID equals menu.SystemId into MM
select new OnLoginData
{
lstTableDetails = conDb.TableMasters
.Where(table => table.SystemId == admin.SystemID)
.Select(o => new TableDetails
{
TableId = o.TableId,
TableName = o.TableName,
TableNumber = o.TableNumber
}),
//Same for lstCategoryDetails
};
You Can't use .ToList() inside select so you can change OnLoginData To IEnumerable
public class OnLoginData
{
public IEnumerable<TableDetails> lstTableDetails { get; set; }
public IEnumerable<CategoryDetails> lstCategoryDetails { get; set; }
}

How to join tables using LINQ to Entities query?

I have a simple db structure:
public class Person
{
[Key]
public int PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Transport
{
[Key]
public int TransportID { get; set; }
public string Model { get; set; }
public string Brand { get; set; }
}
public class Accident
{
[Key]
public int AccsidentID { get; set; }
public DateTime AccidentDate { get; set; }
public int TransportID { get; set; }
[ForeignKey("TransportID")]
public virtual Transport Transport { get; set; }
public int PersonID { get; set; }
[ForeignKey("PersonID")]
public virtual Person Person { get; set; }
}
I need to create a list of accidents, wich I could pass to WPF form (using MVVM)
First I created new class witch I would like to see in my GridControl
public class AccsidentObject
{
[Key]
public int AccidentID { get; set; }
public DateTime AccidentDate { get; set; }
public int TransportID { get; set; }
public string Model { get; set; }
public string Brand { get; set; }
public int PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Could you please give me examples:
if I want to get list of all values from Accident table including data from Transport and Person tables
if I want to get Accident list grouped by TransportID (also include data from Person and Transport tables)
I am getting data from Linq query:
var result = from ac in DBContext.Accidents select ac;
List<Accident> accidentList = result.toList();
But I need to add some fields to list from other tables, what would be a code?
What do I do wrong and could not construct a list of AccidentObject, maybe there are some mistake in my DBContext, lists o something... Could you please help me to understand List elements??
Considering to 2 part I wrote:
var result = from ac in DBContext.Accidents select ac;
result = result.GroupBy(g => g.TransportID).toList();
And now I need to add some Transport details and format AccsidentObject list ...
To get an entity (or collection of entities) with associations eagerly populated use the Include extension method, or include in a final projection into your type:
var res = await (from a in ctx.Accidents
select new AccsidentObject {
AccidentID = a.AccidentID,
TransportID = a.Transport.TransportID,
Model = a.Transport.Model,
// …
}).ToListAsync();
You can use groupby in a LINQ comprehension expression to group by something. In the result the Key property is the thing grouped by and each instance is a collection of all things grouped by.
var res = await (from a in ctx.Accidents
group by a.TransportID into g
select new {
TransportID = g.Key,
Accidents = g
}).ToListAsync();
In the resulting anonymous types the Accidents property with be a collection of Accident.
var accidents = DBContext.Accidents.Select( a => new AccidentObject
{
AccidentID = a.AccidentId,
AccidentDate
TransportID
Model
Brand = a.Transport.Brand,
PersonID = a.Person.PersonID,
FirstName
LastName
});
and fill in the blanks in much the same way.
here's a linq example without using lambda expressions, that includes a group by clause if you prefer it: Linq to sql select into a new class

LINQ query: restrict child entity

I'm novice in LINQ, so I need an initial help how to simplify writing of LINQ queries. Here my scenario: I have two tables C_Systemtype with 1:M relationship to CT_Systemtype, using database first approach.
Class C_System:
{
public string SystemtypeId { get; set; }
public bool Is_productive { get; set; }
public bool Is_systemown { get; set; }
public bool Is_active { get; set; }
public byte[] Icon { get; set; }
public virtual ICollection<CT_Systemtype> CT_Systemtype { get; set; }
public virtual ICollection<C_System> C_System { get; set; }
}
Class CT_Systemtype:
{
public string SystemtypeId { get; set; }
public string LanguageId { get; set; }
public string Title { get; set; }
public string Descript { get; set; }
public virtual C_Systemtype C_Systemtype { get; set; }
public virtual S_Language S_Language { get; set; }
}
I like to select all C_Systemtype but with CT_Systemtype restricted to a given LanguageId.
I believe the following LINQ query is working (p_langId is my parameter):
using (var db = new PaltrConnect())
{ var query = from s in db.C_Systemtype
join t in db.CT_Systemtype on s.SystemtypeId equals t.SystemtypeId
where t.LanguageId == p_langId
select new { s.Is_productive,
s.Is_systemown,
s.Is_active,
s.Icon,
s.CT_Systemtype }
}
The result is of type anonymous. My intention is something like C_Systemtype.Include(t => t.CT_Systemtype) but with additional restriction on CT_Systemtype.
How can I rewrite this query in such a way that I don't have to give each property in the select part and to finally map individual properties?
using (var db = new PaltrConnect())
{
var query = from s in db.C_Systemtype
join t in db.CT_Systemtype on s.SystemtypeId equals t.SystemtypeId
where t.LanguageId == p_langId
select s ;/*s is your C_Systemtype*/
}
Because you are joining two tables together you can't just return a single type. To prevent having to map each property in the select you can use something like AutoMapper.

Categories

Resources