LINQ query to retrieve from one table and then another - c#

I have 2 tables containing the same fields,
e.g. id,name,invoiceNo..etc
I want to use c# ling to get all the data from both tables
I have the below example for 1 table, how do I add the second table?
return query = from tb1 in dataContext.tbl1
select new customer
{
name= tbl1.name
};

You can just use Concat once you have two sequences of the same type.
return dataContext.tbl1.Select(tb1 => new customer()
{
name = tb1.name,
})
.Concat(dataContext.tbl2
.Select(tb2 => new customer()
{
name = tb2.name,
}));
You could use query syntax for the select calls, but I find method syntax preferable in this particular case.

You can use Union or Concat:
query1 = from tb1 in dataContext.tbl1
select new customer
{
name= tbl1.name
};
query2 = from tb2 in dataContext.tbl2
select new customer
{
name= tbl1.name
};
var resQuery = query1.Union(query2);
It would be similar with Concat. Main difference between Union and Concat is that Union removes duplicities from the result.

Related

C# linq expression not pulling the data correctly

I am trying to query two tables and need to pull related records from both the tables. I am using enityframeworkcore 3 One is system versioned table and the other is history table. My resultset is containing data only from history table and not system-versioned table. Could somebody tell me what is wrong with my statement . I am ensured that the personid in the systemversion table matches the history table.
Query
var personNotes = (from pn in _context.PersonNotes
join pnh in _context.PersonNotesHistory on pn.PersonId equals pnh.PersonId
select pn);
return personNotes;
You need to specify the column names you want to return in the result:
var personNotes = (from pn in _context.PersonNotes
join pnh in _context.PersonNotesHistory on pn.PersonId equals pnh.PersonId
select new {
data1 = pn.column1,
data2 = pn.column2,
data3 = pn.column3,
data4 = pnh.column1,
data5 = pnh.column2,
data6 = pnh.column3,
}).ToList();
return personNotes;
Just change the column1, column2, column3 with column names you want to retrieve from the database.
As an alternative to the first answer you may use this syntax:
var personNotes = _context.PersonNotes
.Join(_context.PersonNotesHistory, pn => pn.PersonId, pnh => pnh.PersonId, (pn, pnh) => new
{
pn.Note,
pn.AuthorID,
pn.CreatedBy,
pnh.Note,
pnh.AuthorID,
pnh.CreatedBy
})
.ToList();

Linq query to get get count from multiple tables

I have a query wherein I need to get the count from 2 different tables. Here is a very simple form of the query (my query has more joins and conditions but this is the part I am stuck on):
select (select count(1) from Table1) as One, (select count(1) from Table2) as Two
The following linq queries works but I would like to do the above with a single linq query sent to the SQL Server. This query and many other versions I have tried, result in 2 queries sent to the server:
var query1 = from m in this.Table1 select m;
var query2 = from sr in this.Table2 select sr;
var final = new { One = query1.Count(), Two = query2.Count() };
I also tried this and this also sends 2 queries:
var final = from dummy in new List<int> { 1 }
join one in query1 on 1 equals 1 into ones
join two in query2 on 1 equals 1 into twos
select new { One = ones.Count(), Two = twos.Count()};
You need to make it a single LINQ query that can be translated:
var final = (from m in this.Table1.DefaultIfEmpty()
select new {
One = (from m in this.Table1 select m).Count(),
Two = (from sr in this.Table2 select sr).Count()
}).First();
Note that putting the sub-queries into an IQueryable variable will cause three separate queries to be sent.
Alternatively, since Count() doesn't have a query syntax equivalent, this is a little more compact in lambda syntax:
var final = this.Table1.DefaultIfEmpty().Select(t => new {
One = this.Table1.Count(),
Two = this.Table2.Count()
}).First();

Multiple on clause in LINQ to DataTable Join Query

So I have two DataTables that have the same schema, but different data. I want to join the two tables together where two fields, id3 and print and the same. How would I write this in LINQ?
Right now, this works and gives no compiler errors:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on prod.Field<string>("print") equals agg.Field<string>("print")
select new
{
print = prod.Field<string>("print")
};
But what I really want is this:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on (prod.Field<string>("print") equals agg.Field<string>("print") &&
prod.Field<Int32>("id3") equals agg.Field<Int32><("id3"))
select new
{
print = prod.Field<string>("print")
};
But this gives me compiler errors.
How do I join these two tables together on both the print and the id3 columns?
Regards,
Kyle
Use anonymous objects to join on multiple fields:
var singOneJoin =
from prod in singOneProd.Table.AsEnumerable()
join agg in singOneAgg.Table.AsEnumerable()
on new {
Print = prod.Field<string>("print"),
Id3 = prod.Field<Int32>("id3")
} equals new {
Print = agg.Field<string>("print"),
Id3 = agg.Field<Int32>("id3")
}
select new {
print = prod.Field<string>("print")
};
Keep in mind that anonymous object property names should match.

how to combine two data source into one?

i have records in two tables, and 1 object,
i want to retrieve data from both tables into 1 gridview, (both tables have same fields) i can not have joins because i need to show all rows
here is my code:
var query = from all in DB.Movies
where all.IsActive
select new MoviesObject
{
PhotoId = all.PhotoId,
Title = all.Title,
Description = all.ShortDescription
};
var querytwo = from all in DB.movieslisttwo
where all.IsActive
select new MoviesObject
{
PhotoId = all.PhotoId,
Title = all.Title,
Description = all.ShortDescription
;
return query.ToList();
return query.Concat(query2).ToList();
Alternatively, you can call .Union() to skip duplicates.

How to get data from two SQL tables into .net

Previously, I asked a question about getting data from two tables where I take one row in a table and join it with several rows in another table. Here's the link to that discussion: SQL Select data from two tables (one row -> multiple rows)
Here is my SQL code:
SELECT
customer.fName, customer.lName, phone.phoneNumber
FROM
Customers customer
INNER JOIN phoneNumbers phone ON
customer.customerId = phone.customerId
What I would like to know now is: what is the best way to get this data organized in .net?
Let's suppose I have a C# class as following:
public class CustomerDetails
{
int customerId;
string fname;
string lName;
List<string> phoneNumbers;
}
For the sake of discussion, let's suppose that the above SQL query returns the following result:
fname, lname, phoneNumber
"John", "Smith", "111-111"
"Jane", "Doe", "222-1111"
"Jane", "Doe", "222-2222"
At a glance, I see that I have two customers; one has one phone number and the other has two phone numbers. How can I write code to efficiently parse this in C#?
One option is to use LINQ to create a instance of the CustomerDetails class.
Let me know if you would like an example.
Example 1:
List<CustomerDetails> customers = db.Customers.Select(c => new CustomerDetails(){
customerId = c.customerID,
fname = c.fName,
lName = c.lName,
phoneNumbers = (from p in db.PhoneNumbers where p.customerID == c.customerID select p.phoneNumber1).ToList<String>()});
Example 2:
List<CustomerDetails> custs = (from c in db.Customers
select new CustomerDetails()
{
customerId = c.customerID,
fname = c.fName,
lName = c.lName,
phoneNumbers = (from p in db.PhoneNumbers where p.customerID == c.customerID select p.phoneNumber1).ToList<String>()
}).ToList<CustomerDetails>();
I understand that you are looking for ORM object-relational mapping. In .NET I can recommend IBatis.net or LINQ.
Solution 1:
I assume that the records are sorted by name in the SQL query's results and that you also select the customerID. Appending "ORDER BY customer.fName, customer.lName" to your original query will do the trick.
I'll assume that you get your result in a DataReader, so you can do the following:
// Lets start by declaring a collection for our records
List<CustomerDetails> myRecords = new List<CustomerDetails>();
// Iterate all records from the results and fill our collection
while (yourReader.Read())
{
int customerID = int.Parse(yourReader["customerID"]);
int nrRecords = myRecords.Count;
if (nrRecords > 0 && myRecords[nrRecords - 1].customerId == customerID)
{
myRecords[nrRecords - 1].phoneNumbers.Add(yourReader["phoneNumber"]);
}
else
{
CustomerDetails newCustomerDetails = new CustomerDetails();
newCustomerDetails.customerId = customerID;
newCustomerDetails.fName = yourReader["fName"];
newCustomerDetails.lName = yourReader["lName"];
List<string> phoneNumberList = new List<string>();
phoneNumberList.Add(yourReader["phoneNumber"]);
newCustomerDetails.phoneNumbers = phoneNumberList;
myRecords.Add(newCustomerDetails);
}
}
P.S. If ordering the list is not an option, then you can't just check the latest added records customerid - instead you'll need to iterate through the myRecords list and search for the existance of it. This can be done in many ways including with myRecords.Contains() or with a foreach.
Solution 2:
Do the telephone number grouping directly from SQL. Create a function for selecting a comma separated string with all the telephone numbers of a particular customer:
CREATE FUNCTION [dbo].[GetCommaSeparatedPhoneNumbers]
(
#customerID int
)
RETURNS varchar(max)
AS
BEGIN
declare #output varchar(max)
select #output = COALESCE(#output + ', ', '') + phoneNumbers
from phoneNumbers
where customerId = #customerID
return #output
END
GO
Then you can nicely select the list of all customer you want:
SELECT customerId, dbo.GetCommaSeparatedPhoneNumbers(customerId)
FROM Customers
GROUP BY customerId
This will return:
"John", "Smith", "111-111"
"Jane", "Doe", "222-1111,222-2222"
Now it's all a question of parsing the results with a foreach or while loop, but no checking for existance is needed. Just split the string at ',' and insert the values into the List. If there is a chance, that there will be no phone numbers for some customers, then you can filter that field for null.
PS. Will not work if there is a comma as pointed out by BQ in his comment.
Iterate over the result, for each row check if it is in your list of costumers, if not, add a new one, if yes, add the phone number to the existing one.
Of course, you shouldn't parse the string use appropiate classes to access the database, like ado.net.

Categories