• 카테고리
    • 전체 글

    • 카테고리1
    • 카테고리2
    • 카테고리3
    • 카테고리4
  • 태그
  • 방명록

DataRow 유틸-Util 함수를 만들자

기술자료/.NET 2012. 9. 25. 09:34

서두

System.Data.DataRow

데이터베이스 기반의 CS나 Web 관련 개발을 하면 DataTable을 많이 활용하는데, 이 때 데이터들은 DataRow를 통해서 전달 받게 된다. 그런데, 이 DataRow에 담긴 값들은 모두 Object 형식으로 담겨 있는데, 이 때 데이터를 끄집어 내는데, 그냥 ASP 시절의 웹 프로그래밍 방식을 따르게 되면 오류 발생율이 높다. 물론 의도적으로 try ~ catch 문에서 끄집어 내기 위해서 만들기도 하지만, 단순히 데이터를 끄집어 오는데, try ~ catch로 잡아야 될 정도면 개인적으로는 아니다 싶을 때가 많다.

 

본문

예를 들면, Person 이라는 테이블이 있는데, Name - varchar(50), Age – int, Address – varchar(100) 의 형태의 테이블이 있다고 하자.

Name Age Address
Goshe Mack 12 Gangnam
Park Sung-ook 23 [NULL]
Sonia Aka 22 Mapo

데이터테이블이 dtResult 라는 변수에 담겨 있다고 한다면,

   
string sName = dtResult.Rows[0]["Name"].ToSting();

하면 그 해당하는 값인 “Goshe Mack” 이라는 데이터가 나온다.

여기서 발생할 수 있는 오류의 형태는 2가지.

첫번째로는 데이터가 없을 때다. 즉 dtResult 안에 DataRow가 하나도 없으면 저기서 에러가 난다. [0] 부분은 0번째 Row를 가져오겠다는 말인데, 그 안에 앖이 없으면 Null 이고 Null에 대한 [Name]은 없으므로 에러다.

두번째로는 Name 부분이 DbNull 인 경우다. 이 경우 [0][Name] 결과가 null 이 되므로, null의 ToString 에서 오류가 발생하게 된다.

그렇다면 이제 Null을 피해보도록 하자.

첫번째의 경우.

foreach(DataRow row in dtResult.Rows)
{
       string sName = row["Name"].ToString();
}

라고 하면 일단 Data가 없는 경우에 발생되는 문제는 피할 수 있다. 왜냐면 foreach를 할 때, dtResult 안에 Row가 없으면 더 이상 안의 내용을 처리하지 않기 때문이다.

두번째의 경우는 어떻게 할까?

위의 경우 처럼 직관적으로 표현하자면 이렇게 할 수 있을 것이다.

foreach(DataRow row in dtResult.Rows)
{
    if(row["Name"] != null || row["Name"] != DBNull.Value)
    {
        string sName = row["Name"].ToString();
    }
}

조금 더 다듬어 보자.

row["Name"]
이 너무 자주 나온다!  이것을 조금 더 개선 시키는 방향은 아예 값을 밖으로 빼서 하나의 변수에 넣고, 그 값을 돌려 쓰는 방식을 취한다. 이러면 딱 한번만 row[“Name”] 을 부를 뿐 실제 값은 변수에서 직접 가져와 쓰게 된다.
foreach(DataRow row in dtResult.Rows)
{
    object value = row["Name"];
    if(value != null || value != DBNull.Value)
    {
        string sName = value.ToString();
    }
}

만일 Null 일 때 Default 값을 설정하고 싶다면? 더 간단하다. 이번에는 sName 부분을 위로 끄집어 올린다.

foreach(DataRow row in dtResult.Rows)
{
    string sName = "DEFAULT";
    object value = row["Name"];
    if(value != null || value != DBNull.Value)
    {
        sName = value.ToString();
    }
}

여기까지는 좋다고 생각된다. 그런데, 만일, 여러 개의 필드일 때는 어떻게 할까? 더욱이 String도 아닌 Int 같은 필드 인 경우 ToString 으로 해결도 안된다. 한번 위의 방식대로 코드를 짜보자

foreach(DataRow row in dtResult.Rows)
{
    string sName = "DEFAULT";
    int nAge = 0;
    string sAddress = "DEFAULT";

    object value = row["Name"];
    if(value != null || value != DBNull.Value)
    {
        sName = value.ToString();
    }

    object value = row["Address"];
    if(value != null || value != DBNull.Value)
    {
        sAddress = value.ToString();
    }

    object value = row["Age"];
    if(value != null || value != DBNull.Value)
    {
        string sTemp = value.ToString();
        try
        {
            nAge = int.Parse(sTemp);
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

}

갑자기 길어지는 코드!!!!

지금은 값이 세 개니까, 저렇지 만일 필드수가 10개 이상된다고 하면, 값 한번 조회하는 코드만 100라인 넘게 된다. 까잇거 Copy&Paste 신공이 있는데! 라고 외치며 무식하게 짜시는 분이 계신다면, 나중에 그 코드를 유지보수해야 할 때 참여하는 자신 혹은 남을 위해 자제해주셨으면 한다. 제발 ㅋ

그래서 아예 값을 별도로 처리하기 위한 Util 형태의 Static 클래스를 만들어 사용하는 방법을 추천한다.

/// 
/// System.Data.DataRow의 데이터를 쉽게 접근하기 위해서 사용되는 함수 모음
/// 
static public class DBUtils
{

    /// 
    /// DataRow 상에서 특정 Coloumn 이름에 해당하는 문자열을 읽어온다.
    /// 별도 기본값을 제공하여 읽어오는데 실패한 경우 입력받은 기본값으로 돌려준다.
    /// 
    /// 읽어올 데이터가 담긴 DataRow
    /// 읽어올 데이터의 Column 이름
    /// 읽어오는 것을 실패한 경우 돌려줄 기본값
    /// 읽어온 문자열 값
    public static string ReadString(DataRow row, string sColumnName, string sDefaultValue)
    {
        string sResult = sDefaultValue;
        if (row.Table.Columns.Contains(sColumnName))
        {
            object value = row[sColumnName];
            if ((value is DBNull) == false && value != null)
            {
                sResult = value.ToString();
                    
            }
        }
        sResult = sResult.Trim();
        return sResult;
    }

    /// 
    /// DataRow 상에서 특정 Coloumn 이름에 해당하는 문자열을 읽어온다.
    /// 
    /// 읽어올 데이터가 담긴 DataRow
    /// 읽어올 데이터의 Column 이름    
    /// 읽어온 문자열 값
    public static string ReadString(DataRow row, string sColumnName)
    {
        return ReadString(row, sColumnName, string.Empty);
    }


    /// 
    /// DataRow 상에서 특정 Coloumn 이름에 해당하는 숫자값을 읽어온다.
    /// 별도 기본값을 제공하여 읽어오는데 실패한 경우 입력받은 기본값으로 돌려준다.
    /// 
    /// 읽어올 데이터가 담긴 DataRow
    /// 읽어올 데이터의 Column 이름
    /// 읽어오는 것을 실패한 경우 돌려줄 기본값
    /// 읽어온 숫자 값
    public static int ReadInteger(DataRow row, string sColumnName, int nDefaultValue)
    {
        int nResult = nDefaultValue;
        if (row.Table.Columns.Contains(sColumnName))
        {
            object value = row[sColumnName];
            if ((value is DBNull) == false && value != null)
            {
                string sValue = value.ToString();
                if (int.TryParse(sValue, out nResult) == false)
                    nResult = nDefaultValue;
            }
        }
        return nResult;
    }

    /// 
    /// DataRow 상에서 특정 Coloumn 이름에 해당하는 숫자값을 읽어온다.
    /// 
    /// 읽어올 데이터가 담긴 DataRow
    /// 읽어올 데이터의 Column 이름
    /// 읽어온 숫자 값
    public static int ReadInteger(DataRow row, string sColumnName)
    {
        return ReadInteger(row, sColumnName, 0);
    }

    /// 
    /// DataRow 상에서 특정 Coloumn 이름에 해당하는 DateTime값을 읽어온다.
    /// 별도 기본값을 제공하여 읽어오는데 실패한 경우 입력받은 기본값으로 돌려준다.
    /// 
    /// 읽어올 데이터가 담긴 DataRow
    /// 읽어올 데이터의 Column 이름
    /// 읽어오는 것을 실패한 경우 돌려줄 기본값
    /// 읽어온 DateTime 값
    public static DateTime ReadDateTime(DataRow row, string sColumnName, DateTime defaultTime)
    {
        DateTime result = defaultTime;
            
        if (row.Table.Columns.Contains(sColumnName))
        {
            object value = row[sColumnName];
            if ((value is DBNull) == false && value != null)
            {
                try
                {
                    result = (DateTime)value;
                }
                catch (Exception ex)
                {
                    Core.LogWriter.Current.Write(ex);
                }
                //try
                //{
                //    result = DateTime.Parse(sValue);
                //}
                //catch
                //{
                //}
            }
        }
        return result;
    }


    /// 
    /// DataRow 상에서 특정 Coloumn 이름에 해당하는 DateTime값을 읽어온다.
    /// 
    /// 읽어올 데이터가 담긴 DataRow
    /// 읽어올 데이터의 Column 이름
    /// 읽어온 DateTime 값
    public static DateTime ReadDateTime(DataRow row, string sColumnName)
    {
        return ReadDateTime(row, sColumnName, DateTime.MinValue);
    }

    public static System.Data.SqlTypes.SqlBinary ReadSQLBinary(DataRow row, string sColumnName)
    {
        System.Data.SqlTypes.SqlBinary result = System.Data.SqlTypes.SqlBinary.Null;

        if (row.Table.Columns.Contains(sColumnName))
        {
            object value = row[sColumnName];
            if ((value is DBNull) == false && value != null)
            {
                try
                {
                    result = new System.Data.SqlTypes.SqlBinary((byte[])value);                        
                }
                catch (Exception ex)
                {
                    Core.LogWriter.Current.Write(ex);
                }
                //try
                //{
                //    result = DateTime.Parse(sValue);
                //}
                //catch
                //{
                //}
            }
        }
        return result;

    }
}

저런 클래스를 만들면 위에서 제시한 예제 코드는 다음 형태로 변하게 된다.

foreach(DataRow row in dtResult.Rows)
{
    string sName = DBUtils.ReadString(row,"Name","DEFAULT");
    int nAge = DBUtils.ReadInteger(row,"Age",0);
    string sAddress = DBUtils.ReadString(row,"Address","DEFAULT");
}

 

정리

반복적인 작업을 보다 효율적으로 빠르게 처리하라고 있는 컴퓨터에서 노가다하고 있는 우리네 현실을 보면 조금 답답한 것 같다. 사실 C#에는 프로그래머에게 보다 더 편리하고 간단하게 짜라는 장치가 많다. 하지만, 100% 현실에 맞는 것은 아닌 것 같다.

하나씩 자신만의 Util을 만들어 자신의 코드 내에 있는 노가다의 요소들을 정리해보는 것은 어떨까?

728x90
블로그 이미지

하인도1

[하인드/하인도/인도짱 의 홈페이지] 저만의 공간입니다. 다양한 소재들을 나열하는 아주 단순 무식한 홈페이지 입니다. 다양한 문서 자료도 있겠지만, 저의 푸념들도 있답니다.

250x250

블로그 내에 소스 코드 삽입 이사온 기념 스킨도... RSS 전문 기능 비활성화 관련. 스킨 바꾸어 보았습니다. 서버 파일 정리 좀 했습니다.

«   2025/06   »
일 월 화 수 목 금 토
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

비스킷 me2photo Visual Studio 인터파크 오류 Buscuit e-book Azure 협업 개발환경 블로그 WSS 매뉴얼 windows me2dayzm Tutorial 것 친구 좀 me2sms 불만 twi2me 수 지름신 MOSS 2007 SharePoint moss Google Apps Engine 2010 java

  • Total :
  • Today :
  • Yesterday :

Copyright © 2015-2025 Socialdev. All Rights Reserved.

Copyright © 2015-2025 Socialdev. All Rights Reserved.

티스토리툴바