LINQ Left Join и Right Join
Мне нужна помощь,
У меня есть две dataTable, называемые A и B, мне нужны все строки из A и соответствующая строка B
Пример:
A: B:
User | age| Data ID | age|Growth
1 |2 |43.5 1 |2 |46.5
2 |3 |44.5 1 |5 |49.5
3 |4 |45.6 1 |6 |48.5
Мне нужен Out Put:
User | age| Data |Growth
------------------------
1 |2 |43.5 |46.5
2 |3 |44.5 |
3 |4 |45.6 |
Ответы
Ответ 1
Приведенные данные примера и вывода не показывают левого соединения. Если бы это было левое соединение, ваш результат будет выглядеть так (обратите внимание, как у нас есть 3 результата для пользователя 1, то есть один раз для каждой записи роста, которую имеет пользователь 1):
User | age| Data |Growth
------------------------
1 |2 |43.5 |46.5
1 |2 |43.5 |49.5
1 |2 |43.5 |48.5
2 |3 |44.5 |
3 |4 |45.6 |
Предполагая, что вам все еще требуется левое соединение; здесь, как вы делаете левое соединение в Linq:
var results = from data in userData
join growth in userGrowth
on data.User equals growth.User into joined
from j in joined.DefaultIfEmpty()
select new
{
UserData = data,
UserGrowth = j
};
Если вы хотите сделать правильное соединение, просто замените таблицы, которые вы выбираете из них, например:
var results = from growth in userGrowth
join data in userData
on growth.User equals data.User into joined
from j in joined.DefaultIfEmpty()
select new
{
UserData = j,
UserGrowth = growth
};
Важной частью кода является оператор in, а затем DefaultIfEmpty. Это говорит Linq, что мы хотим иметь значение по умолчанию (т.е. Null), если в другой таблице нет соответствующего результата.
Ответ 2
Доктор Джонс показал левое внешнее соединение, но правильный ответ был бы немного другим - потому что в исходном вопросе должны использоваться две таблицы, связанные с полем возраста, чтобы получить результат точно так, как нужно, следующий код.
....
//ctx = dataContext class - not shown here.
var user1 = new UserData() { User = 1, Age = 2, Data = 43.5 };
var user2 = new UserData() { User = 2, Age = 3, Data = 44.5 };
var user3 = new UserData() { User = 3, Age = 4, Data = 45.6 };
ctx.UserData.AddRange(new List<UserData> { user1, user2, user3 });
var growth1 = new UserGrowth() { Id = 1, Age = 2, Growth = 46.5 };
var growth2 = new UserGrowth() { Id = 1, Age = 5, Growth = 49.5 };
var growth3 = new UserGrowth() { Id = 1, Age = 6, Growth = 48.5 };
ctx.UserGrowth.AddRange(new List<UserGrowth> { growth1, growth2, growth3 });
var query = from userData in ctx.UserData
join userGrowth in ctx.UserGrowth on userData.Age equals userGrowth.Age
into joinGroup
from gr in joinGroup.DefaultIfEmpty()
select new
{
User = userData.User,
age = userData.Age,
Data = (double?)userData.Data,
Growth = (double?)gr.Growth
};
Console.WriteLine("{0} | {1} | {2} | {3}", "User", "age", "Data", "Growth");
foreach (var x in query)
{
Console.WriteLine("{0} | {1} | {2} | {3}", x.User, x.age, x.Data, x.Growth);
}
.... with following entity classes:
public class UserData
{
[Key]
public int User { get; set; }
public int Age { get; set; }
public double Data { get; set; }
}
public class UserGrowth
{
public int Id { get; set; }
public int Age { get; set; }
public double Growth { get; set; }
}
Ответ 3
Простой способ - использовать ключевое слово Let. Это работает для меня.
from AItem in Db.A
Let BItem = Db.B.Where(x => x.id == AItem.id ).FirstOrDefault()
Where SomeCondition
Select new YourViewModel
{
X1 = AItem.a,
X2 = AItem.b,
X3 = BItem.c
}
Это симуляция левого соединения. Если каждый элемент в таблице B не соответствует элементу A, BItem возвращает ноль
Ответ 4
Простой пример
модель
class Employee
{
public string Name { get; set; }
public int ID { get; set; }
public int ProjectID { get; set; }
}
class Project
{
public int ProjectID { get; set; }
public string ProjectName { get; set; }
}
Methord
public void leftrighjoin(){
Project P1 = new Project() { ProjectID = 1, ProjectName = "UID" };
Project P2 = new Project() { ProjectID = 2, ProjectName = "RBS" };
Project P3 = new Project() { ProjectID = 3, ProjectName = "XYZ" };
// Employee List
List<Employee> ListOfEmployees = new List<Employee>();
ListOfEmployees.AddRange((new Employee[]
{
new Employee() { ID = 1, Name = "Sunil", ProjectID = 1 },
new Employee() { ID = 1, Name = "Anil", ProjectID = 1 },
new Employee() { ID = 1, Name = "Suman", ProjectID = 2 },
new Employee() { ID = 1, Name = "Ajay", ProjectID = 3 },
new Employee() { ID = 1, Name = "Jimmy", ProjectID = 4 }}));
//Project List
List<Project> ListOfProject = new List<Project>();
ListOfProject.AddRange(new Project[] { P1, P2, P3 });
//Left join
var Ljoin = from emp in ListOfEmployees
join proj in ListOfProject
on emp.ProjectID equals proj.ProjectID into JoinedEmpDept
from proj in JoinedEmpDept.DefaultIfEmpty()
select new
{
EmployeeName = emp.Name,
ProjectName = proj != null ? proj.ProjectName : null
};
//Right outer join
var RJoin = from proj in ListOfProject
join employee in ListOfEmployees
on proj.ProjectID equals employee.ProjectID into joinDeptEmp
from employee in joinDeptEmp.DefaultIfEmpty()
select new
{
EmployeeName = employee != null ? employee.Name : null,
ProjectName = proj.ProjectName
};
//Printing result of left join
Console.WriteLine(string.Join("\n", Ljoin.Select(emp => " Employee Name = " +
emp.EmployeeName + ", Project Name = " + emp.ProjectName).ToArray<string>()));
//printing result of right outer join
Console.WriteLine(string.Join("\n", RJoin.Select(emp => " Employee Name = " +
emp.EmployeeName + ", Project Name = " + emp.ProjectName).ToArray<string>()));
}