LING to SQL에서 다중 결과 셋 받기

Posted in .NET Framework // Posted at 2012. 11. 13. 20:04
728x90

현재 카테고리에 맞지 않는 영역이지만....

관리도 안될게 뻔한 카테고리를 새로 만들고 싶지 않아 ASP.NET MVC 카테고리에 꺼적인다

 

ASP.NET MVC로 DB 관련 개발할 때,

EntityFramework 나 LING to SQL을 사용하곤 한다

 

근데 이 두 넘은 다 좋은데, 저장 프로시저의 다중 결과 셋을 지원하지 않는다.

 

음.. 지원하지 않는다기 보다는 자동으로 생성되는 designer.cs에만 의존하면 그렇다고 해야 정확한 표현인 듯 싶다.

 

예를 들어,

게시판 글 보기 페이지일 경우, 글 내용과 해당 글에 대한 댓글 정보를 하나의 프로시저에서 두 개의 결과 셋으로 반환하도록 할 경우 처음으로 반환된 결과 셋이 자동으로 바인딩 되는 것이다

 

물론 이런 상황이라면 글 내용은 OUTPUT 변수로 받고 댓글 리스트는 결과셋으로 받아서 해결 가능하다. 실제로 이렇게 사용한 적이 꽤 많다.

 

그러나 문제는 정말로 리스트형태의 결과 셋이 여러 개일 경우이다. 이젠 더 이상 OUTPUT 반환 값에 의존할 수 없게 되었다.

 

저장프로시저의 시나리오는 대략 이렇다.

1. OUTPUT 변수로 몇 가지 값을 반환한다

2. 3개의 결과 셋(레코드 셋이라는 표현을 좋아하는 사람이 있다)도 같이 반환한다

 

그러니깐, 의미적으로 총 3가지 형태의 결과값을 받고 싶은 게다

(OUTPUT 반환 값 + 결과셋1 + 결과셋2 + 결과셋3)

 

물론 결과셋의 개수는 중요치 않다. 두 개 이상의 결과셋을 반환한다는 게 중요하다

 

이제 이 프로시저를 LINK to SQL로 연동해서 결과를 처리하고 싶다

 

먼저 desiner.cs 가 자동 생성한 아래의 코드를 보자

 [global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.USP_GetGameView")]
  public ISingleResult<USP_GetGameViewResult> USP_GetGameView([global::System.Data.Linq.Mapping.ParameterAttribute(Name="GameNo", DbType="SmallInt")] System.Nullable<short> gameNo, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="GameName", DbType="NVarChar(100)")] ref string gameName, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="Score", DbType="Decimal(2,1)")] ref System.Nullable<decimal> score, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="Description", DbType="NVarChar(400)")] ref string description)
  {
   IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), gameNo, gameName, score, description);
   gameName = ((string)(result.GetParameterValue(1)));
   score = ((System.Nullable<decimal>)(result.GetParameterValue(2)));
   description = ((string)(result.GetParameterValue(3)));
   return ((ISingleResult<USP_GetGameViewResult>)(result.ReturnValue));
  }

 

매우 복잡한(?) 코드에 의미 두지 말자. designer.cs 가 자동 생성해 준 코드를 그대로 옮긴 것이니..

그리고 저장프로시저의 원형에 의미도 두지 말자. 그냥 대충 다중 셋을 반환하는 저장프로시저라고 생각하면 된다. 중요한 것은 ISingleResult를 반환한다는 점이다. 그래서 다중 결과 셋의 첫 번째 결과만 바인딩 되는 것이다.

 

그렇다면 해결책은 ISingleResult가 아닌 다중 셋을 반환할 수 있도록 IMultipleResults을 반환하면 된다.

이를 위한 새로운 메서드를 정의해야 하는 데, designer.cs가 자동 생성한 클래스를 사용할 생각은 말아야 한다. DB 연동이 추가/제거/변경 될 경우 이 클래스는 다시 생성되기 때문에 자신의 코드가 모두 사라질 수 있기 때문이다.

 

그렇기 때문에 파티셜 클래스 기법을 이용하면 된다.

 

designer.cs가 생성한 클래스와 동일한 이름으로 파티셜 클래스를 선언하고 다중 셋을 반환할 수 있도록 다음과 같이 작성할 수 있다

public partial class MobileDBDataContext
    {
        [Function(Name = "dbo.USP_GetGameView")]
        [ResultType(typeof(ScreenShot))]
        [ResultType(typeof(Video))]
        [ResultType(typeof(CommentInfo))]       
        public IMultipleResults GetGameView(short? gameNo, ref string gameName, ref decimal? score, ref string description)
        {
            IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), gameNo, gameName, score, description);
            gameName = ((string)(result.GetParameterValue(1)));
            score = ((System.Nullable<decimal>)(result.GetParameterValue(2)));
            description = ((string)(result.GetParameterValue(3)));

            return (IMultipleResults) result.ReturnValue;
        }
    }

 

자동생성된 이전의 코드와 거의 유사한 것을 알 수 있다

다른 점이라면 IMultipleResults 타입을 반환한다는 점과, 다중 셋의 결과를 자동으로 바인딩 하기 위한 클래스 선언이 있다는 점이다.

 

LINQ to SQL을 사용하면서 다중 결과 셋에 대한 목마름이 있었던 사람은 위의 코드만으로도 그 즉시 적용가능하리라 본다.

 

 

 

 

'.NET Framework' 카테고리의 다른 글

Generic DataContract in WCF  (0) 2013.05.09
WCF Data Service VS ASP.NET Web API  (2) 2013.01.08
MVC 다중 폼 유효성 체크  (0) 2012.09.07
Razor 구문  (0) 2011.07.19
ASP.NET Razor  (5) 2010.12.13