Get details from 2 tables asp.net web api - c#

I'm creating a web api. I have two tables
Employee_details
SlNo Employeeid R_ID
1 2022 AC1
2 2023 AC2
Id_details
SlNo R_ID L_ID
1 AC1 L001
2 AC1 L002
3 AC1 L003
4 AC2 L004
5 AC2 L005
I created a web api with RESTful services. I need to get all the L_ID of a particular Employeeid. For example if I request for employeeid 2022 I should get L001 L002 and L003. Help me please. I created the tables using code first and enabling migration
Code
Model class
Employee_details.cs
public class Employee_details
{
public int slNo {get; set;}
public string Employeeid {get; set;}
public string R_ID {get; set;}
//Navigation
public Id_details Id_details{get; set;}
}
Id_details.cs
public class Id_details
{
public int slNo {get; set;}
public string R_ID {get; set;}
public string L_ID {get; set;}
}
Controller
public IQueryable<Employee_id> Getdetails(string employeeid )
{
return db.Employee_details
.Where(b => b.Employeeid.Equals(employeeid, StringComparison.OrdinalIgnoreCase)).Include(c => c.Id_details);
}
I did not make foreign key reference since R_ID field in Table 2 is not a primary key.

If you use Native SQL this query is your return data.
SELECT ID.L_ID
FROM Id_details AS ID
INNER JOIN Employee_details ED
ON ID.R_ID = ED.R_ID
WHERE ED.Employeeid = '2022'
or if you use EntitiyFramework
this query return equels R_ID records then set Employee_details condition
var res = db.Id_details.Join(db.Employee_details, x => x.R_ID , y => y.R_ID , (x, y) => x).ToList();
or you can select any R_ID in containsList
var conditionList =db.Employee_details.where(p=>p.Employeeid.equals('2022')).select(p=>p.R_ID);
then set condition using conditionList search
db.Id_details.where(p=> conditionList.contains(p.R_ID)).select ( ... );

Related

Dapper binding doesnt work in multi mapping

TThis is my dto.Worker table:
| id | first_name | current_branch |
|----|------------|----------------|
| 1 | Adam | 5 |
This is how I fetch data from this table:
public async Task<WorkerDTO> GetById(int workerId)
{
using (var connection = connectionFactory.GetConnection())
{
string sQuery = $#"SELECT * FROM dto.Worker WITH(NOLOCK) WHERE id = #WorkerId";
return await connection.QueryFirstAsync<WorkerDTO>(sQuery, new { WorkerId = workerId }).ConfigureAwait(false);
}
}
The WorkerDTO class has the same structure as dto.Worker table, but properties doesn't contain _ character:
public class WorkerDTO
{
public int Id {get; set;}
public string FirstName {get; set;}
public int CurrentBranch {get; set;}
}
There is also a dto.Job table:
| id | job_name |
|----|----------|
| 1 | foo |
And dto.WorkerJob table:
| worker_id | job_id |
|-----------|--------|
| 1 | 1 |
I want to fetch all workers and its jobs. I already established that I need to use multi mapping dapper feature. I came with something like this:
public async Task<IEnumerable<WorkerJobDTO>> GetAllWorkersJobs()
{
using (SqlConnection connection = connectionFactory.GetConnection())
{
var sQuery = $#"SELECT worker.*, job.* FROM dbo.Worker worker
LEFT JOIN dbo.WorkerJob workerJob ON workerJob.worker_id = worker.id
LEFT JOIN dbo.Job job ON job.id = workerJob.job_id";
var workers = await connection.QueryAsync<WorkerJobDTO, JobDTO, (WorkerJobDTO workerJob, JobDTO job)>(sQuery, (worker, job) => (worker, job), parameters).ConfigureAwait(false);
return workers.GroupBy(x => x.worker.Id)
.Select(group =>
{
var worker = group.First().worker;
worker.Jobs = group
.Select(x => x.job)
.Where(x => x != null)
.ToList();
return worker;
});
}
}
Unfortunately this doesn't work, because there is a mismatch between WorkerJobDTO properties names and database column names. To fix this, I have to change WorkerJobDTO class from:
public class WorkerJobDTO
{
public int Id {get; set;}
public string FirstName {get; set;}
public int CurrentBranch {get; set;}
public List<JobDTO> Jobs {get; set;}
}
to:
public class WorkerJobDTO
{
public int id {get; set;}
public string first_name {get; set;}
public int current_branch {get; set;}
public List<JobDTO> Jobs {get; set;}
}
Is there any way to fix this without modyfing DTO model's properties names?
You can change the names returned from the query, if you specify each column and an alias. Selecting '*' is anyway not considered best practice as there are some performance hits in the server in comparison with specifying the columns explicitly. Change your query to this:
var sQuery = $#"SELECT worker.id AS Id,
worker.first_name AS Name,
worker.current_branch AS CurrentBranch,
job.* FROM dbo.Worker worker
LEFT JOIN dbo.WorkerJob workerJob ON workerJob.worker_id = worker.id
LEFT JOIN dbo.Job job ON job.id = workerJob.job_id";
That would be a quick fix. However, your multimapping code doesn't look like standard and I don't see what you need WorkerJobDTO for, it is after all, just a link table. I would change the whole thing to something like this:
public async Task<IEnumerable<WorkerJobDTO>> GetAllWorkersJobs()
{
using (SqlConnection connection = connectionFactory.GetConnection())
{
var workerDictionary = new Dictionary<int, WorkerDTO>();
var sQuery = $#"SELECT worker.*, job.* FROM dbo.Worker worker
LEFT JOIN dbo.WorkerJob workerJob ON workerJob.worker_id = worker.id
LEFT JOIN dbo.Job job ON job.id = workerJob.job_id";
var workers = await connection.QueryAsync<WorkerDTO, JobDTO, WorkerDTO>(sQuery,
(worker, job) =>
{
WorkerDTO workerEntry;
if (!workerDictionary .TryGetValue(worker.Id, out workerEntry))
{
workerEntry = worker;
workerEntry.Jobs = new List<JobDTO>(); // only if it's not done in the default constructor
workerDictionary.Add(worker.Id, workerEntry);
}
workerEntry.Jobs.Add(job);
return null; // This doesn't matter, the result will be in workers
}, parameters).ConfigureAwait(false);
}
}
That's pretty much the standard multi-mapping pattern in Dapper and requires no after-burning.

How to extract a specific database column from the query result

I have this SQL query that successfully returns the desired result.
Basically for the given NameId there are multiple unique PlaceId.
SQL query:
Select
NameId, PlaceId
From
db_schemaA_tableA a
Left Join
db_schemaB_tableB b On a.Id = b.NameId
Left Join
db_schemaC_tableC c On a.ItemId = c.ItemId
Where
a.Id = 'C330ads'
NOTE: NameId and PlaceId are of datatype GUID
SQL result:
NameId | PlaceId
---------+----------
C330ads | 705ddf
C330ads | 618rre
In C# this is what I have
Entity class
public class Name
{
public Guid NameId {get; set:}
public Guid PlaceId {get; set;}
}
Class with DB connection method
public List<Name> GetNames(Guid someId)
{
SqlConnection connection = new SqlConnection();
var result = new List<Name>();
string query = #"Select NameId, PlaceId from db_schemaA_tableA a
left join db_schemaB_tableB b on a.Id = b.NameId
left join db_schemaC_tableC c on a.ItemId = c.ItemId
where a.Id= #NameId";
//HOW CAN I GET ALL PlaceIds ?
using(connection)
{
result = connection.Query<Name>(query, new {NameId = someId});
}
return result;
}
How can I get all the corresponding PlaceId for the given NameId in C#?
Thank you
I think you are trying to use Dapper. you can do it in this way.
Add Dapper package if not already added.
using Dapper;
using (var connection = new SqlConnection(connectionString))
{
CommandDefinition command = new CommandDefinition(query, null, null, null, CommandType.Text);
result = connection.Query<List<Name>>(command).ToList();
}
This wasn't a Dapper issue, as I initially thought. It was something much simpler.
I had the columns NameId and PlaceId in sql as such:
NameId | PlaceId
-------------------
C330ads | 705ddf
C330ads | 618rre
In C#, I had to provide the variable/variables I needed to map values to
public Guid Name {get; set;}
public Guid Place{get; set;}
So in my query I had to select both variables:
Select NameId as Name, PlaceId as Place from db_schemaA_tableA ...

Lambda Method Query Syntax with a List within a List

I have my model as:
// Person
public class Person {
public int Id {get; set}
public string FirstName {get; set}
public string LastName {get; set}
public ICollection<PersonCourse> PersonCourses {get; set;}
}
// PersonCourse
public class PersonCourse {
public int PersonId {get; set}
public Person Person {get; set;}
public int CourseId {get; set}
public Course Course {get; set}
}
// Course
public class Course {
public int Id {get; set}
public string Name {get; set}
public ICollection<PersonCourse> PersonCourses {get; set;}
}
I have the following data:
// Person
ID FIRSTNAME LASTNAME
1 John Doe
2 Jane Doe
// PersonCourse
PersonId CourseId
1 1
1 2
2 1
2 3
// Course
ID NAME
1 Course1
2 Course2
3 Course3
How can I write a Lambda Method query to get the data as an IEnumerable as:
John Doe Course1
John Doe Course2
Jane Doe Course1
Jane Doe Course3
Currently, I have the courses listed in a CSV format like below:
// NOTE:
// MUST start query from DBSet<Person> not from DBSet<PersonCourse>!
var data = db.Persons.Select(x => new {
FirstName = x.FirstName,
LastName = x.LastName,
CourseName = string.Join(",", x.PersonCourses.Select(c => c.Course.Name)
});
The best approach for this is:
var data = db.Persons.SelectMany(c => c.PersonCourses.Select(x => c.FirstName + " " + c.LastName + " " + x.Course.Name));
Assuming that everything is not null. I prefer always to manage Null safety, but that depends on the final result that you want (discard if is a single null or fill with empty string)
To get multiple rows per Person you need a Join or a SelectMany.
Using the navigation properties you can do this:
var data = db.Persons.SelectMany
(
p => p.PersonCourses,
(p, pc) => new { p.FirstName, p.LastName, pc.Course.Name }
);
Or you can do the uglier but more general join, avoiding the navigation properties:
var data = db.Persons
.Join
(
db.PersonCourses, p => p.Id, pc => pc.PersonId,
(p, pc) => new { p, pc }
)
.Join
(
db.Courses, j => j.pc.CourseId, c => c.Id,
(j, c) => new { j.p.FirstName, jn.p.LastName, c.Name }
);
Joins work when the navigation properties aren't available (POCOs in memory for instance) and aren't all that hard to work with... except for that pesky intermediate j but you get used to it.

ASP.net JSON Rest API Output from Complex Class from Database

Database Tables
tbl_Product
- id (pk)
- name
- price
tbl_image
- id (pk)
- prd_id (fk)
- imageUrl
I want to the Json result from my database like this
[
{
"id":"",
"name":"",
"price":"",
"images":[
{
"id":"",
"imageUrl":""
},
{
"id":"",
"imageUrl":""
},
{
"id":"",
"imageUrl":""
}
]
},
{
"id":"",
"name":"",
"price":"",
"images":[
{
"id":"",
"imageUrl":""
},
{
"id":"",
"imageUrl":""
}
]
}
]
C# Object Class
class ProductModel
{
public int id {get; set;}
public string name {get; set;}
public string price {get; set;}
public ImageModel images {get; set;}
}
class ImageModel
{
public int id {get; set;}
public int prd_id {get; set;}
public string imageUrl {get; set;}
}
First of all i would like to thank you for reading my simple question.
How to get json output like above ..
I am confused if i join the query to get the output like this ..
select * from tbl_Product a inner join tbl_images b on a.id = b.prd_id
This will result join the two tables, How do i separate it out from Business logic to generate that output ..
or
Do we need to GetAllProduct from tbl_Product table and do for loop and while mapping datatable to object fetch imageByProductId and add to that ProductModel Object ..
I am not sure is this the fastest way .. i don;t want to use entity framework ...
I want just a method which provide me JSON in above format and try to make sure the method is in C# without any framework
Thank you for reading my question and waiting for your ans.
First of all your models need to be like this
class ProductModel
{
public int id {get; set;}
public string name {get; set;}
public string price {get; set;}
public IList<ImageModel> images {get; set;}
}
class ImageModel
{
public int id {get; set;}
public string imageUrl {get; set;}
}
and then try below linq to sql query
tbl_Product.Select(prod =>
new ProductModel
{
id = prod.id,
name = prod.name,
price = prod.price,
images = prod.tbl_image.Select(img => new ImageModel
{
id = img.id,
imageUrl = img.imageUrl
})
}).ToList()
If you are working with Azure SQL Database or you can install SQL Server 2016 then you can add FOR JSON AUTO clause:
select * from tbl_Product a inner join tbl_images b on a.id = b.prd_id
FOR JSON AUTO
This would return you JSON text that you can simply return as response of API.

EF & LINQ: Get object from database cell

I use Entity Framework Code First and I have three tables (for example):
public class Motorbike()
{
public int Id {get; set;}
public string Producent {get; set;}
public Engine Motor {get; set;}
public Tire Tires {get; set;}
}
public class Engine()
{
public int Id {get; set;}
public int Power {get; set;}
public decimal Price {get;set;}
}
public class Tire()
{
public int Id {get; set;}
public int Size {get; set;}
public decimal Price {get; set;}
}
It's just example, in fact it's more complicated.
Entity Frmaework generates table for me, but tables Motorbike has column: Id, Power, Engine_Id (where storing only number - id engine, not whole object) and Tire_Id (where storing only number - id tire, not whole object).
I know how to insert data - just create new Motorbike object, save to his fields data (for Engine and Tire fields I save whole objects not only id) and use .Add() method from my context.
But how to get data for row where motorbike id is (for example) 1?
I've tried something like this:
List<Motorbike> motorbikes= new List<Motorbike>();
var list = _context.Motorbike.Where(p => p.Id == 1);
motorbikes.AddRange(list);
but always I've got null for Engine and Tire fields (fields Id and Producent are fill properly).
Use Include to load related entities like:
var list = _context.Motorbike
.Include(m=> m.Engine)
.Include(m=> m.Tire)
.Where(p => p.Id == 1);
See: Entity Framework - Loading Related Entities
You're looking for the Include() method.
List<Motorbike> motorbikes = _context.Motorbike
.Include(p => p.Engine)
.Include(p => p.Tire)
.Where(p => p.Id == 1)
.ToList();

Categories