안드로이드로 앱 개발을 진행 중인데 PC에서는 C#로 구성된 프로그램에서 DB에 접근한다.

PC에서 이미지 파일을 MS SQL Sever에 binary로 변환하여 업로드하는데, 그걸 안드로이드 앱에서 받아 이미지를 구현하는데 많은 애를 먹어서 작성해본다.

 

이전에 존재했던 DB - APP 정보 송수신은 다음과 같았다.

 

1. Ms SQL Server에 Apache Http Server 설치 ( 고정 IP 설정 )

2. SQL Server와 Apache Http Server간은 JDBC로 통신

3. Apache http Server는 JSP를 통해 XML 서식으로 송신

4. App에서는 XMLparser와 POST 방식을 이용하여 수신

 

일단 문제를 일으키던 XML 형태를 JSON 형태로 바꿔 개발하기 시작했다. 데이터를 잘 받아오던 와중에 binary(max)로 변환된 이미지를 JSON이 제대로 가져오지 못하면서 문제가 생기기 시작했다. 이유인즉슨 binary 값을 받아오기 위해서는 byte[] 형태로 가져와야 하나, JSP에서 출력할 때 이미 toString()으로 변환되어버리기 때문이었다.

 

이미 변환된 String을 byte[]로 바꾸기 위해 App에서 여러가지 시도를 했으나 전부 실패했고, JSP 상에서 Base64를 이용하여 encode하려던 것도 Import를 못 잡아서 시행하지 못했다. 한참 헤매던 끝에, SQL Server에서 query를 작성했을 때, Select 되는 결과를 Base64로 변환하여 올라오도록 수정하였다.

 

SELECT CAST(N'' AS XML).value('xs:base64Binary(xs:hexBinary(sql:column(\"컬럼이름\")))', 'VARCHAR(MAX)') 컬럼이름 FROM 테이블이름

 

그리고 난 후 App 상에서 Base64 변환을 거쳐 ImageView에 setImageBetmap()을 하니 잘 올라갔다. 도식은 다음과 같다.

 

  String checkImage = array.getJSONObject(i).getString("컬럼이름"); //받아온 String 데이터
  byte[] encodeByte = Base64.decode(checkImage, Base64.DEFAULT);
  Bitmap bitmap = BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);
  bitmap = Bitmap.createScaledBitmap(bitmap,  600 ,600, true); // 크기변환
  imageView.setImageBitmap(bitmap);

 

아마 JSP에서 base64를 이용하여 JSON에 변환된 결과값을 담는 방법도 있을 것이다. JSP에 익숙하지 않아도 Server단에서 base64로 변환하는 방법도 있다는걸 정리하고 싶었다.

DevExpress에서는 열별 Summary를 GroupFooter를 통해 자동 생성을 지원하고 있습니다.

GroupField와 xrTableCell별 DataBinding을 이용하면 쉽게 소계와 합계를 낼 수 있습니다.

 

다만 다음과 같은 상황을 생각해봅시다.

 

[QUNT] [COST] [TLAM]

 

수량[QUNT]과 단가[COST]를 곱해서 결과[TLAM]를 내야 하는데, Detail이나 GroupFooter인 경우, xrTableCell을 기준으로 접근할 수가 없습니다.

왜냐하면, Detail과 GroupFooter는 테이블의 상태에 따라 자동으로 갯수가 변화하게 되는데, 객체 자체는 하나로 계속 유지되기 때문입니다.

그런고로 Event를 잡아서 xrTableCell.Text를 꺼내봐도 아무것도 없으며, String을 넣는다 하더라도 Report에 반영되지 않습니다.

 

먼저는 자동 생성하는 셀 객체를 찾아야 합니다. 그러기 위해서는 먼저 찾고자 하는 셀의 'BeforePrint' Event 메소드를 생성합니다. (속성에서 생성가능)

생성하고 나면 매개변수는 다음과 같습니다.

 

private void xrTableCell_BeforePrint(object sender, System.Drawing.Printing.PrintEventArgs e)

 

sender 오브젝트를 XRTableCell으로 캐스팅하면 라인이 추가로 생성될 때마다 생성되는 Cell을 가져올 수 있습니다.

그래서 예를 들어 다음과 같이 하면 생성될 때마다 Cell에 값을 찍을 수 있습니다.

 

XRTableCell cell = (XRTableCell) sender;

cell.Text = "SomeThing";

 

특정한 값을 가져오기 위해서는 조금 복잡합니다. cell의 Text값은 Print 되기 전에는 빈 값입니다.

그리고 XRTableCell의 내부 변수에는 Value 값이 없습니다. Report에서 보이는 단일 사각형과 관련된 정보(디자인적 요소)만 있다고 생각하시면 됩니다.

그리하여 다음과 같이 돌아가야 특정한 값을 가져올 수 있습니다.

 

XRTableCell cell = (XRTableCell) sender;

XtraReport report = cell.RootReport;

object Value = report.GetCurrentColumnValue("QUNT");

 

위와 같은 상황에서 저 행이 Detail이라면 다음과 같이 매 번 Detail이 생성될 때마다 거기에 현재 찍힐 수량[QUNT] 값을 가져올 수 있습니다.

다만 이의 경우 Summary 등으로 구성된 이름 없는 변수값을 가져올 수가 없습니다.

 

GroupFooter에서 자동으로 Summary된 값을 가져오려면 다음과 같이, cell에 넣어놓은 Summary 메소드를 실행하면 됩니다.

 

XRTableCell cell = (XRTableCell) sender;

object value = cell.Summary.GetResult();

 

다만 이렇게 코딩할 경우, Summary는 구성되어 있지만 값이 없어서 GetResult 결과가 null로 나올 경우, NullPointException 에러가 Print 창에서 발생합니다. 

"개체 참조가 개체의 인스턴스로 설정되지 않았습니다."라고 하며, Debug에서도 잡히지 않습니다.

그런고로 저는 다음과 같이 처리하였습니다.

 

XRTableCell cell = (XRTableCell) sender;

if (cell.Summary.GetResult() == null)

return "SomeErrorThing";

else

return cell.Summary.GetResult();

 

이렇게 구성하시면, 전역변수를 통해 메소드간 데이터를 주고 받고, 행간 수식을 구성하실 수 있습니다.

 

P.S. Summary를 사용하지 않는 행의 경우, RootReport를 통해 아예 현재의 Row을 가져오는 방법도 있습니다. (GroupFooter이기 때문에 이렇게 복잡합니다.)

다음과 같이 짜면, Row를 바로 가져와 내부 행들을 쓸 수 있습니다. (Detail의 경우)

 

XRTableCell cell = (XRTableCell) sender;

XtraReport report = cell.RootReport;

DataRowView currentRow = (DataRowView) report.GetCurrentRow();

object[] rowItem = currentRow.Row.ItemArray;

 

//cell.text = (decimal) rowItem[1] * (decimal) rowItem[2]

C#에서는 강력한 DB 라이브러리를 제공하고 있음에도 제대로 이용하고 있지 못하다. (특히 Linq)

대부분 하드 쿼리를 이용해서 필요한 정보들을 요청하고 정리하는데, 프로그램 상에서 수정할 수 있는 것을 도전해보고 있다.

 

쿼리를 통해 받은 DataTable 객체를 이용하고자 하려니 여러 문제가 생긴다.

가장 간단하게 DataTable에서 Select하고 내용을 쓰려고 하니, Select을 DataRow[]를 반환하는 것이다.

이걸 foreach 혹은 for 문을 돌려 새로운 DataTable 객체에 넣으려니 분통이 터진다.

알고보니 그렇게 할 필요가 없다.

DataTable Table = SomeTable.Select("SomeThing = '100'").CopyToDataTable();

위와 같이 하면, 데이터 테이블을 반환한다.

다만 이렇게 할 경우, Select 이후 DataRow가 0일 경우 에러가 발생한다.

DataRows[] dataRows = SomeTable.Select("SomeThing = '100'")
if(dataRows == null || dataRows.Length == 0)
	return;
DataTable Table = dataRows.CopyToDataTable();

그렇기 때문에 위와 같이 에러 처리를 해주는 것이 좋다.

'C#' 카테고리의 다른 글

[C#] 컨테이너 번호 에러 체크 container number digit check  (1) 2022.09.22

+ Recent posts