Microsoft MVP성태의 닷넷 이야기
.NET Framework: 548. Linq는 결국 메서드 호출! [링크 복사], [링크+제목 복사],
조회: 23398
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

Linq는 결국 메서드 호출!

다음과 같은 질문이 있군요. ^^

2개의 DataTable Join 결과 전체 컬럼을 DataTable 로 리턴하기
; https://www.sysnet.pe.kr/3/0/3701

정리해 보면, 다음과 같은 식으로 DataTable이 마련되어 있을 때,

DataTable dtResult = new DataTable();
dtResult.Columns.Add("ID", typeof(string));
dtResult.Columns.Add("name", typeof(string));
dtResult.Columns.Add("stock", typeof(int));
dtResult.Columns.Add("ID2", typeof(string));
dtResult.Columns.Add("name2", typeof(string));
dtResult.Columns.Add("stock2", typeof(int));

DataTable table1 = new DataTable();

table1.Columns.Add("ID", typeof(string));
table1.Columns.Add("name", typeof(string));
table1.Columns.Add("stock", typeof(int));

table1.LoadDataRow(new object[] { "5", "test1", 500 }, true);
table1.LoadDataRow(new object[] { "6", "test2", 600 }, true);
table1.LoadDataRow(new object[] { "7", "test3", 700 }, true);

DataTable table2 = new DataTable();

table2.Columns.Add("ID2", typeof(string));
table2.Columns.Add("name2", typeof(string));
table2.Columns.Add("stock2", typeof(int));

table2.LoadDataRow(new object[] { "5", "test12", 510 }, true);
table2.LoadDataRow(new object[] { "6", "test22", 610 }, true);
table2.LoadDataRow(new object[] { "7", "test32", 710 }, true);

한번의 LINQ 쿼리로 tabl1과 table2의 join 결과를 dtResult에 담고 싶다는 것입니다. 물론, 질문하신 분의 2가지 Linq 쿼리는 그런 것을 못한다는 것이고, 제가 답변을 한 StackOverflow의 글에서는 그에 대한 해결책이 표현되어 있습니다.

간단합니다. 다음과 같이 해주면 해결됩니다.

var result = from dataRows1 in table1.AsEnumerable()
             join dataRows2 in table2.AsEnumerable()
             on dataRows1.Field<string>("ID") equals dataRows2.Field<string>("ID2")
             select dtResult.LoadDataRow(dataRows1.ItemArray.Concat(dataRows2.ItemArray).ToArray<object>(), false);

DataTable my = result.CopyToDataTable();

실제로 위의 코드를 실행해서 출력해 보면,

DataSet ds = new DataSet("test");
ds.Tables.Add(my);

Console.WriteLine(ds.GetXml());

다음과 같은 결과를 얻습니다.

<test>
  <Table1>
    <ID>5</ID>
    <name>test1</name>
    <stock>500</stock>
    <ID2>5</ID2>
    <name2>test12</name2>
    <stock2>510</stock2>
  </Table1>
  <Table1>
    <ID>6</ID>
    <name>test2</name>
    <stock>600</stock>
    <ID2>6</ID2>
    <name2>test22</name2>
    <stock2>610</stock2>
  </Table1>
  <Table1>
    <ID>7</ID>
    <name>test3</name>
    <stock>700</stock>
    <ID2>7</ID2>
    <name2>test32</name2>
    <stock2>710</stock2>
  </Table1>
</test>

그런데, 여기서 제가 하고 싶은 말은... Linq는 단순한 메서드 호출의 나열에 불과하다는 것입니다. 일례로, 위의 Linq 쿼리에서 select 문을 개선해 볼까요?

var result = from dataRows1 in table1.AsEnumerable()
             join dataRows2 in table2.AsEnumerable()
             on dataRows1.Field<string>("ID") equals dataRows2.Field<string>("ID2")
             select dtResult.LoadDataRow(dataRows1.ItemArray.Concat(dataRows2.ItemArray).ToArray<object>(), false);

가령, 다음과 같이 메서드로 바꿔줄 수 있습니다.

var result = from dataRows1 in table1.AsEnumerable()
             join dataRows2 in table2.AsEnumerable()
             on dataRows1.Field<string>("ID") equals dataRows2.Field<string>("ID2")
             select MergeRows(dtResult, dataRows1, dataRows2);


private static DataRow MergeRows(DataTable table, DataRow dataRows1, DataRow dataRows2)
{
    List<object> list = new List<object>();

    list.AddRange(dataRows1.ItemArray);
    list.AddRange(dataRows2.ItemArray);

    return table.LoadDataRow(list.ToArray(), false);
}

또는, table 정의를 바꾸고 그에 맞게 데이터를 채우는 것도 가능합니다. 가령, 다음은 ID2 컬럼을 제외하고 있습니다.

DataTable dtResult = new DataTable();
dtResult.Columns.Add("ID", typeof(string));
dtResult.Columns.Add("name", typeof(string));
dtResult.Columns.Add("stock", typeof(int));
dtResult.Columns.Add("name2", typeof(string));
dtResult.Columns.Add("stock2", typeof(int));

var result = from dataRows1 in table1.AsEnumerable()
             join dataRows2 in table2.AsEnumerable()
             on dataRows1.Field<string>("ID") equals dataRows2.Field<string>("ID2")
             select MergeRows2(dtResult, dataRows1, dataRows2);

private static DataRow MergeRows2(DataTable table, DataRow dataRows1, DataRow dataRows2)
{
    List<object> list = new List<object>();

    list.AddRange(dataRows1.ItemArray);
    list.AddRange(dataRows2.ItemArray.Skip(1));

    return table.LoadDataRow(list.ToArray(), false);
}

/*
<test>
  <Table1>
    <ID>5</ID>
    <name>test1</name>
    <stock>500</stock>
    <name2>test12</name2>
    <stock2>510</stock2>
  </Table1>
  <Table1>
    <ID>6</ID>
    <name>test2</name>
    <stock>600</stock>
    <name2>test22</name2>
    <stock2>610</stock2>
  </Table1>
  <Table1>
    <ID>7</ID>
    <name>test3</name>
    <stock>700</stock>
    <name2>test32</name2>
    <stock2>710</stock2>
  </Table1>
</test>
*/

이 정도면... 대충 감이 오시죠? ^^

(첨부 파일은 위의 예제 코드를 포함합니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 2/20/2016]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2016-02-22 02시55분
[강준] 답변 감사합니다.
그런데 제가 원했던건 dtResult 가 없는상태에서 결과를 도출할수 없는가 였습니다.^^
A 테이블과 B 테이블의 컬럼을 알 수 없고 키만 같고 결과로는 키와 함께 다른 컬럼들도 같이해서
결과를 보고 싶었던것입니다.^^
일단 이런 방법도 있는 걸 알게 되었네요
[guest]
2016-02-22 03시03분
제가 MergeRows2를 작성한 것은 그에 대한 다양한 요구 사양을 만족시킬 수 있다는 것을 알려드린 것입니다. dtResult를 굳이 안 받아도 전달받은 DataRow 2개의 컬럼 값을 런타임시에 알아내서 dtResult를 임의로 구성해 처리할 수 있습니다. (물론, 매번 구성하면 성능 손실이 심각하니 static 유형의 캐시 관리를 추가해야 할 것입니다.)

그러니까, 이 글에서는 Linq를 제약된 환경으로 인식하지 말고 예전의 메서드 호출과 동일하게 보라는 것입니다.

즉 Linq를 생각하지 말고, 2개의 DataRow가 조합된 데이터들을 어떻게 DataTable에 넣을 수 있을까요?.... 와 같은 문제입니다.
정성태
2016-02-22 04시10분
[강준] 네 말씀하신데로 런타임시에는 알수가 있어서 그렇게 처리를 하긴 했습니다.^^
암튼 linq 내에서 메서드 호출이 가능하다는걸 알았네요
(람다식을 이용하면 먼가 제약이 있던데..)
답변 감사합니다~

[guest]

... 46  47  48  49  50  51  52  53  54  [55]  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12599정성태4/14/202118865.NET Framework: 1038. C# - 인증서 및 키 파일로부터 pfx/p12 파일을 생성하는 방법파일 다운로드1
12598정성태4/14/202119827.NET Framework: 1037. openssl의 PEM 개인키 파일을 .NET RSACryptoServiceProvider에서 사용하는 방법 (2)파일 다운로드1
12597정성태4/13/202118647개발 환경 구성: 569. csproj의 내용을 공통 설정할 수 있는 Directory.Build.targets / Directory.Build.props 파일
12596정성태4/12/202117911개발 환경 구성: 568. Windows의 80 포트 점유를 해제하는 방법
12595정성태4/12/202118513.NET Framework: 1036. SQL 서버 - varbinary 타입에 대한 문자열의 CAST, CONVERT 변환을 C# 코드로 구현
12594정성태4/11/202117934.NET Framework: 1035. C# - kubectl 명령어 또는 REST API 대신 Kubernetes 클라이언트 라이브러리를 통해 프로그래밍으로 접근 [1]파일 다운로드1
12593정성태4/10/202118468개발 환경 구성: 567. Docker Desktop for Windows - kubectl proxy 없이 k8s 대시보드 접근 방법
12592정성태4/10/202118114개발 환경 구성: 566. Docker Desktop for Windows - k8s dashboard의 Kubeconfig 로그인 및 Skip 방법
12591정성태4/9/202122209.NET Framework: 1034. C# - byte 배열을 Hex(16진수) 문자열로 고속 변환하는 방법 [2]파일 다운로드1
12590정성태4/9/202118679.NET Framework: 1033. C# - .NET 4.0 이하에서 Console.IsInputRedirected 구현 [1]
12589정성태4/8/202119208.NET Framework: 1032. C# - Environment.OSVersion의 문제점 및 윈도우 운영체제의 버전을 구하는 다양한 방법 [1]
12588정성태4/7/202121531개발 환경 구성: 565. PowerShell - New-SelfSignedCertificate를 사용해 CA 인증서 생성 및 인증서 서명 방법
12587정성태4/6/202122872개발 환경 구성: 564. Windows 10 - ClickOnce 배포처럼 사용할 수 있는 MSIX 설치 파일 [1]
12586정성태4/5/202119730오류 유형: 710. Windows - Restart-Computer / shutdown 명령어 수행 시 Access is denied(E_ACCESSDENIED)
12585정성태4/5/202118561개발 환경 구성: 563. 기본 생성된 kubeconfig 파일의 내용을 새롭게 생성한 인증서로 구성하는 방법
12584정성태4/1/202119777개발 환경 구성: 562. kubeconfig 파일 없이 kubectl 옵션만으로 실행하는 방법
12583정성태3/29/202120177개발 환경 구성: 561. kubectl 수행 시 다른 k8s 클러스터로 접속하는 방법
12582정성태3/29/202120124오류 유형: 709. Visual C++ - 컴파일 에러 error C2059: syntax error: '__stdcall'
12581정성태3/28/202120022.NET Framework: 1031. WinForm/WPF에서 Console 창을 띄워 출력하는 방법 (2) - Output 디버깅 출력을 AllocConsole로 우회 [2]
12580정성태3/28/202117748오류 유형: 708. SQL Server Management Studio - Execution Timeout Expired.
12579정성태3/28/202118498오류 유형: 707. 중첩 가상화(Nested Virtualization) - The virtual machine could not be started because this platform does not support nested virtualization.
12578정성태3/27/202118929개발 환경 구성: 560. Docker Desktop for Windows 기반의 Kubernetes 구성 (2) - WSL 2 인스턴스에 kind가 구성한 k8s 서비스 위치
12577정성태3/26/202120316개발 환경 구성: 559. Docker Desktop for Windows 기반의 Kubernetes 구성 - WSL 2 인스턴스에 kind 도구로 k8s 클러스터 구성
12576정성태3/25/202118658개발 환경 구성: 558. Docker Desktop for Windows에서 DockerDesktopVM 기반의 Kubernetes 구성 (2) - k8s 서비스 위치
12575정성태3/24/202117128개발 환경 구성: 557. Docker Desktop for Windows에서 DockerDesktopVM 기반의 Kubernetes 구성 [1]
12574정성태3/23/202122810.NET Framework: 1030. C# Socket의 Close/Shutdown 동작 (동기 모드)
... 46  47  48  49  50  51  52  53  54  [55]  56  57  58  59  60  ...