Я наследовал базу данных, которая не была разработана точно оптимально, и я должен управлять некоторыми данными. Позвольте мне дать более общую аналогию вида вещи, которую я должен сделать:
Скажем, у нас есть a Student
таблица, a StudentClass
учет ведущего таблицы всех классов он принял участие, и a StudentTeacher
таблица, которая хранит всех учителей, которые учили этого студента. Да, я знаю, что это - немой дизайн, и имело бы больше смысла хранить учителя на таблице Class - но это - то, с чем мы работаем.
Я теперь хочу очистить данные, и я хочу найти все места, где у студента есть учитель, но никакие классы, или класс, но никакие учителя. SQL таким образом:
select *
from StudentClass sc
full outer join StudentTeacher st on st.StudentID = sc.StudentID
where st.id is null or sc.id is null
Как дела это в Linq?
Я думаю, у меня есть ответ здесь, что не так элегантно, как я надеялся, но он должен сделать трюк:
var studentIDs = StudentClasses.Select(sc => sc.StudentID)
.Union(StudentTeachers.Select(st => st.StudentID);
//.Distinct(); -- Distinct not necessary after Union
var q =
from id in studentIDs
join sc in StudentClasses on id equals sc.StudentID into jsc
from sc in jsc.DefaultIfEmpty()
join st in StudentTeachers on id equals st.StudentID into jst
from st in jst.DefaultIfEmpty()
where st == null ^ sc == null
select new { sc, st };
Вы, вероятно, могли выжать эти два утверждения в одну, но Я думаю, что вы пожертвоваете ясность кода.
Начало ...
var q = from sc in StudentClass
join st in StudentTeachers on sc.StudentID equals st.StudentID into g
from st in g.DefaultIfEmpty()
select new {StudentID = sc.StudentID, StudentIDParent = st == null ? "(no StudentTeacher)" : st.StudentID...........};
См. Также http://www.linqpad.net/ для получения дополнительных образцов Хороший инструмент для игры с
Я предлагаю вам преобразовать ваши данные в новую структуру данных, такую, как это:
name_data {
string name;
int[] amounts;
}
Вы бы связываете ваш повторитель в список (name_data>.
, чтобы создать это, во-первых, итерации через
и данные
списки списки и сохраняют список (список, вероятно) всех уникальных лет, которые вам нужно сообщать о. Сортировать результирующий список, так что годы в порядке. Теперь индексы списка лет Соответствуйте номерам столбцов в вашей выходной таблице. Далее, повторяется переписывание элемента
, на этот раз создание нового объекта name_data для каждого элемента
объект. Имя_data конструктор будет выглядеть так :
public name_data(string name, int yearCount) {
this.name = name;
amounts = new int[yearCount];
}
Годка - это количество предметов в списке «Год».
Наконец, шаг через список данных
для текущего элемента
, посмотрите в год в год Список, чтобы получить индекс, затем наклейте значение суммы в поле суммы в соответствующем слоте
. Добавьте ваше заполненное name_data в список.
на CE Вы сделали, вы должны быть в состоянии связать список имени_дата к вашему ретрему
-121--4378960-Для данных 2 коллекций A и B , требуемое полное наружное соединение может быть следующим:
a.Union(b).Except(a.Intersect(b));
Если A и B не Из того же типа, то 2 отдельные нелевые внешние соединения требуются:
var studentsWithoutTeachers =
from sc in studentClasses
join st in studentTeachers on sc.StudentId equals st.StudentId into g
from st in g.DefaultIfEmpty()
where st == null
select sc;
var teachersWithoutStudents =
from st in studentTeachers
join sc in studentClasses on st.StudentId equals sc.StudentId into g
from sc in g.DefaultIfEmpty()
where sc == null
select st;
Вот один вариант, используя Concat ():
(from l in left
join r in right on l.Id equals r.Id into g
from r in g.DefaultIfEmpty()
where r == null
select new {l, r})
.Concat(
from r in right
join sc in left on r.Id equals sc.Id into g
from l in g.DefaultIfEmpty()
where l == null
select new {l, r});