Skocz do zawartości
Tartar

[C#][linq] Problem z left join

Rekomendowane odpowiedzi

Witam

Mam problem ze zrobieniem left join'a w linq.

Chcę połączyć te dwa DataTable:

dt_JOINOEZAM.Columns.Add("NAJ_OE_TOW", typeof(string)); 
dt_JOINOEZAM.Columns.Add("ID_TOW", typeof(int)); 
dt_JOINOEZAM.Columns.Add("ID_TOWZAM1", typeof(int));
dt_JOINOEZAM.Columns.Add("ID_TOWZAM2", typeof(int)); 
dt_JOINOEZAM.Columns.Add("ID_TOW_DO", typeof(int)); 
dt_JOINOEZAM.Columns.Add("NAJ_OE_ZAM", typeof(string)); 
/*ta niżej ma być połączona w lewo do tej powyżej*/
dt_F_Varchar.Columns.Add("ID_X1", typeof(int)); 
dt_F_Varchar.Columns.Add("ID_X2", typeof(int));
dt_F_Varchar.Columns.Add("ID_F_VARCHAR1", typeof(int)); 
dt_F_Varchar.Columns.Add("ID_F_VARCHAR2", typeof(int)); 
dt_F_Varchar.Columns.Add("WARTOSC", typeof(string));

 

Wynik ma trafić do tabeli jak niżej:

dt_KONCOWA.Columns.Add("NAJ_OE_TOW", typeof(string));
dt_KONCOWA.Columns.Add("ID_TOW", typeof(int));
dt_KONCOWA.Columns.Add("ID_TOWZAM1", typeof(int));
dt_KONCOWA.Columns.Add("ID_TOWZAM2", typeof(int));
dt_KONCOWA.Columns.Add("ID_TOW_DO", typeof(int));
dt_KONCOWA.Columns.Add("NAJ_OE_ZAM", typeof(string));
dt_KONCOWA.Columns.Add("ID_F_VARCHAR1", typeof(int));
dt_KONCOWA.Columns.Add("ID_F_VARCHAR2", typeof(int));
dt_KONCOWA.Columns.Add("WARTOSC", typeof(string));

 

Tutaj jest kod tego połączenia (nie jestem dobry w linqu więc mogłem coś sknocić - zrobiłem to na podstawie danych z neta):

var query = (from d1 in dt_JOINOEZAM.AsEnumerable()
	join d2 in dt_F_Varchar.AsEnumerable()
	on new { A = d1.Field<int>("ID_TOWZAM2"), B = d1.Field<int>("ID_TOWZAM1") } equals new { A = d2.Field<int>("ID_X2"), B = d2.Field<int>("ID_X1") }
	into grupaKoncowa
	from d in grupaKoncowa.DefaultIfEmpty()
	select new
	{
	NAJ_OE_TOW = d1.Field<string>("NAJ_OE_TOW"),
	ID_TOW = d1.Field<int>("ID_TOW"),
	ID_TOWZAM1 = d1.Field<int>("ID_TOWZAM1"),
	ID_TOWZAM2 = d1.Field<int>("ID_TOWZAM2"),
	ID_TOW_DO = d1.Field<int>("ID_TOW_DO"),
	NAJ_OE_ZAM = d1.Field<string>("NAJ_OE_ZAM"),
	ID_F_VARCHAR1 = d.Field<int?>("ID_F_VARCHAR1") == null ? -1000 : d.Field<int>("ID_F_VARCHAR1"),
	ID_F_VARCHAR2 = d.Field<int?>("ID_F_VARCHAR2") == null ? -1000 : d.Field<int>("ID_F_VARCHAR2"),
	WARTOSC = d.Field<string>("WARTOSC") ?? ""
	}).AsQueryable();

var qSel = from q in query
	select dt_KONCOWA.LoadDataRow(new object[]
	{
	q.NAJ_OE_TOW,
	q.ID_TOW,
	q.ID_TOWZAM1,
	q.ID_TOWZAM2,
	q.ID_TOW_DO,
	q.NAJ_OE_ZAM,
	q.ID_F_VARCHAR1,
	q.ID_F_VARCHAR2,
	q.WARTOSC
	}, false);
dt_KONCOWA = qSel.CopyToDataTable();

 

Przy takim kodzie dla pierwszego zapytania dostaję taki błąd:

System.ArgumentNullException: Wartość nie może być zerowa.

Nazwa parametru: row

w System.Data.DataRowExtensions.Field[T](DataRow row, String columnName)

w NocnyBilans.MainForm.<>c.<Lacz_VARCHAR>b__31_7(<>f__AnonymousType1`2 <>h__TransparentIdentifier0, DataRow d) w C:\Users\XRay\source\repos\NocnyBilans\NocnyBilans\MainForm.cs:wiersz 503

w System.Linq.Enumerable.<SelectManyIterator>d__23`3.MoveNext()

w System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()

w System.Data.DataTableExtensions.LoadTableFromEnumerable[T](IEnumerable`1 source, DataTable table, Nullable`1 options, FillErrorEventHandler errorHandler)

w System.Data.DataTableExtensions.CopyToDataTable[T](IEnumerable`1 source)

w NocnyBilans.MainForm.Lacz_VARCHAR(DataTable dt_joinoezam, DataTable dt_varchar, DataTable dt_wynik, Stopwatch czas_wykonania) w C:\Users\XRay\source\repos\NocnyBilans\NocnyBilans\MainForm.cs:wiersz 529

Wiersz 503 to "select new", wiersz 529 to "dt_KONCOWA = qSel.CopyToDataTable();".

Jak nie dam tego

ID_F_VARCHAR1 = d.Field<int?>("ID_F_VARCHAR1") == null ? -1000 : d.Field<int>("ID_F_VARCHAR1"),

ID_F_VARCHAR2 = d.Field<int?>("ID_F_VARCHAR2") == null ? -1000 : d.Field<int>("ID_F_VARCHAR2"),

WARTOSC = d.Field<string>("WARTOSC") ?? ""

to wszystko jest OK, jednak jak dam tylko np.: ID_F_VARCHAR1 = d.Field<int>("ID_F_VARCHAR1") to od razu błąd.

 

Zrobiłem "małe" obejście tego problemu jednak nie wiem ile na tym stracę czasowo i mocowo:

foreach (DataRow dr in dt_joinoezam.Rows)
{
	string warunek = string.Format("ID_X1 = {0} AND ID_X2 = {1}", dr["ID_TOWZAM1"], dr["ID_TOWZAM2"]);
	DataRow[] selWynik = dt_varchar.Select(warunek);
	if (selWynik.Length == 0)
	{
	dt_wynik.Rows.Add(dr["NAJ_OE_TOW"], dr["ID_TOW"], dr["ID_TOWZAM1"], dr["ID_TOWZAM2"], dr["ID_TOW_DO"], dr["NAJ_OE_ZAM"], -1000, -1000, "");
	}
	else
	{
	dt_wynik.Rows.Add(dr["NAJ_OE_TOW"], dr["ID_TOW"], dr["ID_TOWZAM1"], dr["ID_TOWZAM2"], dr["ID_TOW_DO"], dr["NAJ_OE_ZAM"], selWynik[0]["ID_F_VARCHAR1"], selWynik[0]["ID_F_VARCHAR2"], selWynik[0]["WARTOSC"]);
	}
}

 

Obecne ilości wierszy w tabelach to (to tylko wycinek danych na których program będzie pracował - dlatego zależy mi na zoptymalizowaniu go):

dt_JOINOEZAM=3917,

dt_F_Varchar=259882,

dt_KONCOWA=3917.

Ilości te będą znacznie większe.

 

Drugie pytanie mniej ważne (ale do statystyk programu potrzebne - optymalizacja bo komp docelowy ze znacznie mniejszą pamięcią RAM będzie) - po każdej funkcji robię process.WorkingSet64 co niby ma mi dać zajętość aktualnego procesu. Problemem jest to że dane te są cały czas takie same i nie wiem jak się zmienia zajętość pamięci po dołożeniu danych do tabel.

 

Z góry dziękuję.

 

Wesołych Świąt a przede wszystkim dużo Zdrowia życzę.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się

  • Ostatnio przeglądający   0 użytkowników

    Brak zarejestrowanych użytkowników przeglądających tę stronę.

×
×
  • Dodaj nową pozycję...