Conditional Join In LINQ? - c#

I am trying to write a query that grabs information from one database and joins it to information in a different database.
TableA
idA
valueA
idB
TableB
idB
valueB
The tricky part is that in TableA, idB isn't always defined, so when I do a normal join, I only get results where TableA has a idB value. What I want is to be able to grab all of the information from TableA even if it doesn't have a corresponding idB value.

Here is a query expression syntax version of the left join to follow up on tvanfosson's answer.
var query = from rowA in db.TableA
join rowB in db.TableB
on rowA.idB equals rowB.idB into b
from item in b.DefaultIfEmpty()
select new
{
idA = rowA.idA,
valueA = rowA.valueA,
idB = rowA.idB,
valueB = item != null ? item.valueB : 0 // or other default value
};

Use a left outer join by checking if the value returned from the right hand side is null and supplying a default value for that case.
var q = db.TableA.Join( db.TableA,
a => a.idB,
b => b.idB,
(a,b) => new
{
A = a.ValueA,
B = b == null ? null : b.ValueB
});

You can do a left outer join in LINQ with SelectMany (directly calling Queryable methods) or in comprehension syntax join ... into:
var results = from a in db.TableA
join b in db.TableB on a.idB equals b.idB
into found
select new {
A = a,
Bs = found
};
In the output Bs will be IEnumerable<typeof-db-TableB>

Left Join Example:
var leftOuterJoinQuery =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from item in prodGroup.DefaultIfEmpty(new Product{Name = String.Empty, CategoryID = 0})
select new { CatName = category.Name, ProdName = item.Name };

Related

LEFT JOIN in LINQ between dbContext and InMemory List

My tagNumbers is of List<string> type. I need to do a left join on this List with database. Currently when I start a trace on database, I see as many queries getting fired as many no of records are in this list. Also this LINQ query gives an error when using LEFT JOIN i.e. lj.DefaultIfEmpty() since l.TagId will be NULL in case of LEFT JOIN for some of the records
i.e.
SELECT * FROM tagNumbers LEFT JOIN TagCollections ON.....LEFT JOIN...
from t in tagNumbers
join tc in dbContext.TagCollections on t equals tc.TagNumber into lj
from l in lj.DefaultIfEmpty()
join m in dbContext.MapTagEntities on l.TagId equals m.TagId
select new GetItemByTagnumberResponse
{
//DO SOMETHING
}
How should I ensure only one query is fired on database no matter how long my list is.
How should I correct my LEFT JOIN from getting an exception
Error
Object reference not set to an instance of an object on join m in dbContext.MapTagEntities on l.TagId equals m.TagId l.TagId because "l" is NULL in case of LEFT JOIN where join condition is not matching.
This could be done using GroupJoin. Here is simple implementation.
// When
var results = fruitIds
.GroupJoin(db.Fruits, id => id, fruit => fruit.Id, (id, fruits) => new
{
id = id,
fruit = fruits.FirstOrDefault()
})
.GroupJoin(db.Attributes, f => f.fruit != null ? f.fruit.Id : 0, att => att.Id, (fruitContainer, attributes) => new
{
id = fruitContainer.id,
fruit = fruitContainer.fruit,
attribute = attributes.FirstOrDefault()
})
.ToList();
// Then
Assert.AreEqual(3, results.Count);
Assert.AreEqual(2, results.Where(r => r.fruit != null).Count());
Assert.AreEqual(1, results.Where(r => r.attribute != null).Count());
Sorry for fruit implementation, I had it already written, I just needed to do proper query.

Convert SQL into linq to sql - group by two columns and request count of a third column

This is how the query looks in SQL:
select count(SnpId_this), DrugId, VariantId from tbl_custom_SNPs_All
join tbl_custom_SNP_Variants on VariantId = SnpsVariantId_this
join tbl_custom_SNP_Drugs_Apelon_NUIs on DrugId = SnpsDrugId_this
group by DrugId, VariantId
Here is my attempt using linq-to-sql:
var drugVariantGroups =
(from a in adminDB.tbl_custom_SNPs_Alls
join v in adminDB.tbl_custom_SNP_Variants
on a.VariantId equals v.SnpsVariantId_this
join d in adminDB.tbl_custom_SNP_Drugs_Apelon_NUIs
on a.DrugId equals d.SnpsDrugId_this
group a by new { a.VariantId, a.DrugId } into dv
select new
{
dv.Key.VariantId,
dv.Key.DrugId,
Entries = dv.Sum()
}).ToList();
looks like dv does not have a definition for sum. How do I access SnpId_this to count it?
Just use Count. You may need to filter any entries where SnpId_this is null if that is a possibility and to precisely match the T-SQL.
Entries = dv.Where(t => t.SnpId_this != null).Count()
You want Count not Sum:
var drugVariantGroups =
(from a in adminDB.tbl_custom_SNPs_Alls
join v in adminDB.tbl_custom_SNP_Variants
on a.VariantId equals v.SnpsVariantId_this
join d in adminDB.tbl_custom_SNP_Drugs_Apelon_NUIs
on a.DrugId equals d.SnpsDrugId_this
group a by new { a.VariantId, a.DrugId } into dv
select new
{
dv.Key.VariantId,
dv.Key.DrugId,
Entries = dv.Count()
}).ToList();
If you want sum you should provide the field to use in Sum function like:
dv.Sum(c=>c.Amount)

Join datatable in c# with null objects

Hello i have a problem joining tables when i have null values in a record.
There are 2 dataTables:
Workers: (workerID, workerName, workerAdress)
Transactions: (transactionID, transactioinValue, worker1, worker2), where worker 2 is optional so it can contain null values.
So i started code like this:
var record = from transaction in dtTransactions.AsEnumerable()
join worker1 in dtWorkers.AsEnumerable() on (int)transactions["worker1"] equals (int)worker1["workerID"]
join worker2 in dtWorkers.AsEnumerable() on (int)transactions["worker2"] equals (int)worker2["workerID"]
select new
{
ID = (int)transactions["transactionID"],
Name1= worker1["workerName"],
Name2= worker2["workerName"]
};
So it all works fine if worker2 isn't null, but when i have a null value it could not be joined. Can someone help me with this problem, i would like to have a result record without a worker2 name if it's null in dataTable.
Is it possible?
you need to do a left join like this;
var record = from transaction in dtTransactions.AsEnumerable()
join worker1 in dtWorkers.AsEnumerable() on (int)transactions["worker1"] equals (int)worker1["workerID"]
join worker2 in dtWorkers.AsEnumerable() on (int)transactions["worker2"] equals (int)worker2["workerID"] into w2
from wrk in w2.DefaultIfEmpty()
select new
{
ID = (int)transactions["transactionID"],
Name1= worker1["workerName"],
Name2= wrk["workerName"]
};
Secondly, is there any reason why you're not specifying the object properties like this;
var record = from transaction in dtTransactions.AsEnumerable()
join worker1 in dtWorkers.AsEnumerable() on (int)transactions.worker1 equals (int)worker1.workerID
join worker2 in dtWorkers.AsEnumerable() on (int)transactions.worker2 equals (int)worker2.workerID into w2
from wrk in w2.DefaultIfEmpty()
select new
{
ID = (int)transactions.transactionID,
Name1= worker1.workerName,
Name2= wrk != null ? wrk.workerName : ""
};
Note the removal of the square brackets
from x in left
where x.Id != null
join y in right on x.Id equals y.Id into rightMatches
from y2 in rightMatches.DefaultIfEmpty()
select new {x, y2};

How to achieve Left Excluding JOIN using LINQ?

How to achieve Left Excluding JOIN using LINQ?
In SQL:
SELECT <select_list>
FROM Table_A A
LEFT JOIN Table_B B
ON A.Key = B.Key
WHERE B.Key IS NULL
You need DefaultIfEmpty() for the LEFT JOIN, then you can check if the joined value is null:
var result = from a in Table_A
join b in Table_B on a.Key equals b.Key into j
from b in j.DefaultIfEmpty()
where b == null
select new { ... };
Easier would be to write like this:
var result = from a in Table_A
where !Table_B.Any(b => b.Key == a.key)
select new { ... };
An even faster way
var result = from a in Table_A
where !Table_B.Select(b => b.Key).Contains(a.Key)
select new { ... };

What is the syntax for an inner join in LINQ to SQL?

I'm writing a LINQ to SQL statement, and I'm after the standard syntax for a normal inner join with an ON clause in C#.
How do you represent the following in LINQ to SQL:
select DealerContact.*
from Dealer
inner join DealerContact on Dealer.DealerID = DealerContact.DealerID
It goes something like:
from t1 in db.Table1
join t2 in db.Table2 on t1.field equals t2.field
select new { t1.field2, t2.field3}
It would be nice to have sensible names and fields for your tables for a better example. :)
Update
I think for your query this might be more appropriate:
var dealercontacts = from contact in DealerContact
join dealer in Dealer on contact.DealerId equals dealer.ID
select contact;
Since you are looking for the contacts, not the dealers.
And because I prefer the expression chain syntax, here is how you do it with that:
var dealerContracts = DealerContact.Join(Dealer,
contact => contact.DealerId,
dealer => dealer.DealerId,
(contact, dealer) => contact);
To extend the expression chain syntax answer by Clever Human:
If you wanted to do things (like filter or select) on fields from both tables being joined together -- instead on just one of those two tables -- you could create a new object in the lambda expression of the final parameter to the Join method incorporating both of those tables, for example:
var dealerInfo = DealerContact.Join(Dealer,
dc => dc.DealerId,
d => d.DealerId,
(dc, d) => new { DealerContact = dc, Dealer = d })
.Where(dc_d => dc_d.Dealer.FirstName == "Glenn"
&& dc_d.DealerContact.City == "Chicago")
.Select(dc_d => new {
dc_d.Dealer.DealerID,
dc_d.Dealer.FirstName,
dc_d.Dealer.LastName,
dc_d.DealerContact.City,
dc_d.DealerContact.State });
The interesting part is the lambda expression in line 4 of that example:
(dc, d) => new { DealerContact = dc, Dealer = d }
...where we construct a new anonymous-type object which has as properties the DealerContact and Dealer records, along with all of their fields.
We can then use fields from those records as we filter and select the results, as demonstrated by the remainder of the example, which uses dc_d as a name for the anonymous object we built which has both the DealerContact and Dealer records as its properties.
var results = from c in db.Companies
join cn in db.Countries on c.CountryID equals cn.ID
join ct in db.Cities on c.CityID equals ct.ID
join sect in db.Sectors on c.SectorID equals sect.ID
where (c.CountryID == cn.ID) && (c.CityID == ct.ID) && (c.SectorID == company.SectorID) && (company.SectorID == sect.ID)
select new { country = cn.Name, city = ct.Name, c.ID, c.Name, c.Address1, c.Address2, c.Address3, c.CountryID, c.CityID, c.Region, c.PostCode, c.Telephone, c.Website, c.SectorID, Status = (ContactStatus)c.StatusID, sector = sect.Name };
return results.ToList();
You create a foreign key, and LINQ-to-SQL creates navigation properties for you. Each Dealer will then have a collection of DealerContacts which you can select, filter, and manipulate.
from contact in dealer.DealerContacts select contact
or
context.Dealers.Select(d => d.DealerContacts)
If you're not using navigation properties, you're missing out one of the main benefits on LINQ-to-SQL - the part that maps the object graph.
Use Linq Join operator:
var q = from d in Dealer
join dc in DealerConact on d.DealerID equals dc.DealerID
select dc;
basically LINQ join operator provides no benefit for SQL. I.e. the following query
var r = from dealer in db.Dealers
from contact in db.DealerContact
where dealer.DealerID == contact.DealerID
select dealerContact;
will result in INNER JOIN in SQL
join is useful for IEnumerable<> because it is more efficient:
from contact in db.DealerContact
clause would be re-executed for every dealer
But for IQueryable<> it is not the case. Also join is less flexible.
Actually, often it is better not to join, in linq that is. When there are navigation properties a very succinct way to write your linq statement is:
from dealer in db.Dealers
from contact in dealer.DealerContacts
select new { whatever you need from dealer or contact }
It translates to a where clause:
SELECT <columns>
FROM Dealer, DealerContact
WHERE Dealer.DealerID = DealerContact.DealerID
Inner join two tables in linq C#
var result = from q1 in table1
join q2 in table2
on q1.Customer_Id equals q2.Customer_Id
select new { q1.Name, q1.Mobile, q2.Purchase, q2.Dates }
Use LINQ joins to perform Inner Join.
var employeeInfo = from emp in db.Employees
join dept in db.Departments
on emp.Eid equals dept.Eid
select new
{
emp.Ename,
dept.Dname,
emp.Elocation
};
Try this :
var data =(from t1 in dataContext.Table1 join
t2 in dataContext.Table2 on
t1.field equals t2.field
orderby t1.Id select t1).ToList();
OperationDataContext odDataContext = new OperationDataContext();
var studentInfo = from student in odDataContext.STUDENTs
join course in odDataContext.COURSEs
on student.course_id equals course.course_id
select new { student.student_name, student.student_city, course.course_name, course.course_desc };
Where student and course tables have primary key and foreign key relationship
try instead this,
var dealer = from d in Dealer
join dc in DealerContact on d.DealerID equals dc.DealerID
select d;
var Data= (from dealer in Dealer join dealercontact in DealerContact on dealer.ID equals dealercontact.DealerID
select new{
dealer.Id,
dealercontact.ContactName
}).ToList();
var data=(from t in db.your tableName(t1)
join s in db.yourothertablename(t2) on t1.fieldname equals t2.feldname
(where condtion)).tolist();
var list = (from u in db.Users join c in db.Customers on u.CustomerId equals c.CustomerId where u.Username == username
select new {u.UserId, u.CustomerId, u.ClientId, u.RoleId, u.Username, u.Email, u.Password, u.Salt, u.Hint1, u.Hint2, u.Hint3, u.Locked, u.Active,c.ProfilePic}).First();
Write table names you want, and initialize the select to get the result of fields.
from d1 in DealerContrac join d2 in DealerContrac on d1.dealearid equals d2.dealerid select new {dealercontract.*}
One Best example
Table Names : TBL_Emp and TBL_Dep
var result = from emp in TBL_Emp join dep in TBL_Dep on emp.id=dep.id
select new
{
emp.Name;
emp.Address
dep.Department_Name
}
foreach(char item in result)
{ // to do}

Categories

Resources