C# Lambda Join Retrieve First Row Values - c#

I have two tables, Table1 and Table2. Table1 has 1 to many relationship with Table2.
Table1 has ListId, ListName
Table2 has FirstName, LastName, Phone, ListId, CustomField1, CustomField2
What I want to retrieve is All rows from Table1 but only retrieve CustomField2 value of Table2 for only 1st row.
The existing query I have below is retrieving me all rows from Table2 which I do not want.
var result = _db.Lists
.Join(_db.ListUsers, c => c.ListID, d => d.ListID, (c, d) => new { c, d });
My final resultset need to look like this
Table1.ListId, Table1.ListName, Table2.CustomField2
1, first list, "abc"
2, second list, "def"

This should do the trick, get only the first record on the right table:
from i in _db.Lists
let p = _db.ListUsers.Where(p2 => i.ListID == p2.ListID).FirstOrDefault()
select new
{
ListID = i.ListID,
ListName = i.ListName,
CustomField2 = p.CustomField2
}
With lambda expression, it would be:
_db.Lists
.Select (
i =>
new
{
i = i,
p = _db.ListUsers
.Where (p2 => i.ListID == p2.ListID))
.Take(1)
.FirstOrDefault()
})
.Select (
results =>
new
{
ListID= results.i.ListID,
ListName = results.i.ListName,
CustomField2 = results.p.CustomField2
}
)

From what I read, the result you want to achieve is retrieve a list of results contains All columns from Table1 & 1 column from Table2 (Not rows).
There are few ways to do this. I would use create a DTO class to retrieve my results. And in the select , you would need to specifically list out the item in your select result.
For example,
Create a DTO class
public class DTOListResult
{
public string XXX {get; set;}
...
}
Then in your result, you can write in this way.
var result = (from a in _db.Lists select new DTOListResult { XXX = _db.table2.ID,
xxx = a.ID,
XXX = a.XX});

Related

Implement ASP.NET MVC5 search functionality using 2 tables

I have created two tables: Claim and ClaimAttachments.
I'm trying to join them on ClaimID in order to get the filtered data from both the tables.
public ActionResult Index(int? search)
{
if (search!=null)
{
var Product = (from P in db.Claims
join C in db.ClaimAttachments on
P.ClaimID equals C.ClaimID
select new Claim
{
ClaimID = P.ClaimID,
ClaimBatchID = P.ClaimBatchID,
PatientControlNumber = P.PatientControlNumber,
PatientFirstName = P.PatientFirstName,
PatientLastName = P.PatientLastName,
ServiceFromDate = P.ServiceFromDate,
ServiceToDate = P.ServiceToDate,
});
return View(db.Claims.Where(x => x.ClaimID == search).ToList());
}
else
{
return View(db.Claims.ToList());
}
I'm able to get the searched result but from single table. The join is not working.
Currently you're only selecting from the Claims data:
return View(db.Claims.Where(x => x.ClaimID == search).ToList());
You have a join query just above that line of code:
var Product = (from P in db.Claims
join C in db.ClaimAttachments on
P.ClaimID equals C.ClaimID
select new Claim
{
ClaimID = P.ClaimID,
ClaimBatchID = P.ClaimBatchID,
PatientControlNumber = P.PatientControlNumber,
PatientFirstName = P.PatientFirstName,
PatientLastName = P.PatientLastName,
ServiceFromDate = P.ServiceFromDate,
ServiceToDate = P.ServiceToDate
});
But you don't do anything with the results of that query. It sounds like you meant to use the results of that query (which is in the Product variable, which incidentally should probably have a plural name since it's a collection) instead of just selecting from db.Claims. Something like this:
return View(Product.Where(x => x.ClaimID == search).ToList());
Note however that you're still only selecting data from one table. Though the join operation may alter the results of that selection. But the selection itself is here:
select new Claim
{
ClaimID = P.ClaimID,
ClaimBatchID = P.ClaimBatchID,
PatientControlNumber = P.PatientControlNumber,
PatientFirstName = P.PatientFirstName,
PatientLastName = P.PatientLastName,
ServiceFromDate = P.ServiceFromDate,
ServiceToDate = P.ServiceToDate
}
Notice how every value selected is from the P alias, which is defined here:
from P in db.Claims
So you're successfully joining the two tables, but only selecting data from one of the two tables. If you want to also select data from the other table then, well, you need to select data from the other table. For example, if there's a property on that table called SomeProperty that you want to select then you'd need to select it, and into an object which has that property.
For example, you might create a view model (let's call it ClaimViewModel as an example) which represents a combined record of the two tables, containing the properties you want from each. Then you'd select into that type:
select new ClaimViewModel
{
ClaimID = P.ClaimID,
ClaimBatchID = P.ClaimBatchID,
PatientControlNumber = P.PatientControlNumber,
PatientFirstName = P.PatientFirstName,
PatientLastName = P.PatientLastName,
ServiceFromDate = P.ServiceFromDate,
ServiceToDate = P.ServiceToDate,
SomeProperty = C.SomeProperty // <--- here
}
This would select the combined data into a list of ClaimViewModel objects, which you'd then filter based on your "search" and return to your view just like you do with the Claims objects now. And of course that view would need to be updated to expect a collection of ClaimViewModel objects instead of a collection of Claim objects.

List<T> joins DataTable

I have a List of objects (lst) and DataTable (dt). I want to join the lst and dt on the common field (code as string) and need to return all matching rows in the lst.
My List contains two columns i.e code and name along with values below:
code name
==== ====
1 x
2 y
3 z
The DataTable contains two columns i.e code and value along with values below:
code value
==== =====
3 a
4 b
5 c
The result is:
3 z
Below is my code; but I know it is not a correct statement and thus seeking your advice here. I would be much appreciated if you could guide me on how to write the correct statement.
var ld = from l in lst
join d in dt.AsEnumerable() on l.code equals d.code
select new { l.code, l.name };
You can use Linq query or Join extension method to join the collection on code. Just that when you select data from datatable, you need to use dt.Field method. Please use either of the following code.
Query1:
var ld = lst.Join(dt.AsEnumerable(),
l => l.code,
d => d.Field<string>("code"),
(l, d) => new
{
l.code,
l.name,
value = d.Field<string>("value")
}).ToList();
Query2:
var ld = (from l in lst
join d in dt.AsEnumerable()
on l.code equals d.Field<string>("code")
select new
{
l.code,
l.name,
value = d.Field<string>("value")
}).ToList();
Query3:
var ld = (from l in lst
join d in dt.AsEnumerable()
on l.code equals d.Field<string>("code")
let value = d.Field<string>("value")
select new
{
l.code,
l.name,
value
}).ToList();
You can try any of the below.
var ld = from l in lst
join d in dt.AsEnumerable() on l.code equals d.Field<int>("code")
select new { l.code, l.name };
var ld = lst.Join(dt.AsEnumerable(), l => l.code, d => d.Field<int>("code"), (l,d) => new { l.code, l.name });
It's not clear what your required output is but it looks as if you are correctly getting the only common records. You could extend your select to
select new { l.code, l.name, d.value }
Which would give all the data/columns from both tables.
code name value
==== ==== =====
3 z a
Try this:
var ld = from l in lst
join d in dt.Cast <DataRow>() on l.code equals d["code"].ToString()
select new { l.code, l.name };
SO you have a List and a DataTable. You don't plan to use the Values of the DataTable, only the Codes.
You want to keep those List items, that have a Code that is also a code in the DataTable.
If you plan to use your DataTable for other things than just for this problem, My advice would be to first create a procedure to convert your DataTable into an enumerable sequence.
This way you can add LINQ statements, not only for this problem, but also for other problems.
Let's create an extension method for your DataTable that converts the data into the items that are in the DataTable. See extension methods demystified.
Alas, I don't know what's in your DataTable, let's assume that your DataTable contains Orders
class CustomerOrder
{
public int Id {get; set;}
public int CustomerId {get; set;}
public int Code {get; set;}
public string Value {get; set;}
...
}
The extension method that extends functionality of class DataTable:
public static IEnumerable<Order> ToCustomerOrders(this DataTable table)
{
return table.AsEnumerable().Select(row => new CustomerOrder
{
Id = ...
CustomerId = ...
Code = ...
Value = ...
};
}
I'm not really familiar with DataTables, but you know how to convert the cells of the row into the proper value.
Usage:
DataTable table = ...
Int customerId = 14;
var ordersOfThisCustomer = table.ToCustomerOrders
.Where(customerOrder => customerOrder.CustomerId == customerId)
.FirstOrDefault();
In words: convert the datatable into CustomerOrders, row by row, and check for every converted CustomerOrder whether it has a CustomerId equal to 14. Stop if found. return null if there is no such row.
Now that you've got a nice reusable procedure that is also easy to test, debug and change, we can answer your question.
Given a DataTable with CustomerOrders, and a sequence of items that contain Code and Name, keep only those items from the sequence that have a Code that is also a Code in the DataTable.
var dataTable = ... // your DataTable, filled with CustomerOrders.
var codeNames = ... // your list with Codes and Names
var codesInDataTable = dataTable.ToCustomerOrders
.Select(customerOrder => customerOrder.Code)
.Distinct();
This will create an enumerable sequence that will convert your DataTable row by row and extract property Code. Duplicate Code values will be removed.
If Codes are unique, you don't need Distinct.
Note: the enumerable sequence is not enumerated yet!
var result = codeNames
.Where(codeName => codesInDataTable.Contains(codeName.Code))
.ToList();
In words: for every [Code, Name] combination in your list, keep only those [Code, Name] combinations that have a value for Code that is also in codesInDataTable.

LINQ Query To Join Two Tables and Select Most Recent Records from Table B corresponding to Table A

I have two tables. Table One contains a list of Areas, and Table Two contains a list of Samples, with each Sample row containing Area_ID as a Foreign Key.
I need to retrieve all the records in my Area table with only the most recent corresponding Sample Status. I have this query, but it just returns one Area with the most recent sample from the Sample table:
var result = (
from a in db.area
join c in db.sample
on a.location_id equals c.location_id
select new
{
name = a.location_name,
status = c.sample_status,
date = c.sample_date
}).OrderByDescending(c => c.date).FirstOrDefault();
A solution could be filtering your second DbSet:
var result = from a in db.area
join c in db.sample.Where(s=>s.location_id==a.location_id).OrderByDescending(c => c.sample_date).Take(1)
on a.location_id equals c.location_id
select new
{
name = a.location_name,
status = c.sample_status,
date = c.sample_date
};
Another solution could be applying a group join:
var result = from a in db.area
join c in db.sample
on a.location_id equals c.location_id into samples
let sample=samples.OrderByDescending(c => c.sample_date).FirstOrDefault()
select new
{
name = a.location_name,
status = sample.sample_status,
date = sample.sample_date
};
If you use navigation properties could be even easier. Supposing you have a one to many relationship between Area and Sample:
var result =from a in db.area
let sample= a.Samples.OrderByDescending(c => c.sample_date).FirstOrDefault()
select new
{
name = a.location_name,
status = sample.sample_status,
date = sample.sample_date
};

How to select a record and only it's children with the highest date in LINQ to SQL

Supose the table "Person" with the fields:
IdPerson, Name, Description.
And the table "FriendVisit" with
IdFriendVisit, Duration, TimeOfVisit, IdPerson
with a relation of 1 to n, where 1 person can have n FriendVisit.
I want to get all the persons with only the last visit in a linq to sql statment.
Somthing like:
var allpersons = this.ObjectContext.Person.Include(p=>p.FriendVisit.OrderBy(fv => fv.TimeOfVisit).FirstOrDefault())
In Reality I only need the Duration of the table FriendVisit and the Name of the table Person, but I don't know if this is relevant.
There is some form of doing it?
I tought of search the data from the children and then iclude the parent... but I would like to do it the "natural" way, call the parent and iclude the children.
ex:
var allVisits = this.ObjectContext.FriendVisit.Include(p=>p.Persons).OrderBy(fv => fv.TimeOfVisit).FirstOrDefault())
You could try this one:
In query syntax
var allPersons = from p in this.ObjectContext.Person
join f in this.ObjectContext.FriendVisit
on p.IdPerson equals f.IdPerson
group by new { p, f }
select new
{
Name = p.Name;
Duration = f.OrderBy(x=>x.TimeOfVisit).Last().Duration
};
or in fluent syntax
var allPersons = this.ObjectContext.Person.Join(this.ObjectContext.FriendVisit,
x=>x.IdPerson,
y=>y.IdPerson
(x,y)=> new { x, y }
).GroupBy(z=>z)
.Select(x=> new
{
Name = p.Name;
Duration = f.OrderBy(y=>y.TimeOfVisit)
.Last()
.Duration
});

Resolve Linq join from Id to value

I'm trying to figure out how to get the results to show the name value instead of the id value on a join of two tables. My tables basically look like this:
VideoCatwegories (table name)
Id,
CategoryName
and
Videos (table name)
Id,
VideoCategory (fk to category table)
Title
Desc
Url
My linq join:
var query = _videoRepository.Table
.Join
(
_videoCategoryRepository.Table,
v => v.Id,
vc => vc.Id,
(v, vc) => new { Videos = v, VideoCategories = vc }
)
.Select(vid => vid.Videos);
The results yield the category id of 1 instead of Instructional etc.
What am I not understanding / doing correctly?
Thank You
First, your join criterion does not look right: it appears that you are joining an id of video to the id of video category, which is probably not set up that way: more likely, video has an id of the corresponding video category, in which case you should use that id in the join.
The rest of your join appear to be fine. The problem is that you are projecting out the results of the join in the Select method. You should remove it, and use the anonymous class to get the data that you need from the joined category, like this:
var query = _videoRepository.Table.Join(
_videoCategoryRepository.Table
, v => v.CategoryId // <<== Use the proper ID here
, vc => vc.Id
, (v, vc) => new { Videos = v, VideoCategories = vc } // <<== This part is fine
);
foreach (var v in query) {
Console.WriteLine("Video: '{0}'
, category '{1}'"
, v.Videos.Name
, v.VideoCategories.Name
);
}
var query =
(from v in _videoRepository
from c in _videoCategoryRepository
where c.Id == v.Id
select new { id = v.id, catname = c.CategoryName, vname = v.Title }
).ToList()

Categories

Resources