Entity Framework 란?
 
Entity Framework 은 논리적인 데이터베이스를 EDM(Entity Data Model) 을 사용하여 추상적인 단계로 끌어올릴 수 있습니다. 보다 쉽게 EDM(Entity Data Model) 을 만들 수 있지만, 운영, 관리적인 면에서는 아직은 미흡한 면이 있네요. 아마도 v2 버전에서는 이러한 고민을 해결할 수 있지 않을까 합니다.
 
Entity Framework 를 보다 자세히 알고 싶으면 아래의 링크를 참조하시기 바랍니다.
 
 
 
EDM(Entity Data Model) 바인딩 문제
 
시작부터 문제가 발생합니다. 우선 Entity Framework 로 작성된 EDM(Entity Data Model) 을 웹 페이지(.ASPX) 에 바인딩 하고자 합니다.
 
아래의 코드는 WCF 서비스를 사용하여 데이터를 조회하여 EDM(Entity Data Model) 을 리턴하는 코드입니다. WCF 서비스에서는 LINQ to Entity 를 사용하여 데이터를 조회하였구요.
 

[그림1] EDM(Entity Data Model) 을 조회하는 코드
 
그리고 아래와 같이 .ASPX 페이지에 EDM(Entity Data Model) 을 바인딩 하는 코드입니다.
[그림2] 웹 페이지(.ASPX) 에서 EDM(Entity Data Model) 바인딩
 
하지만 아래와 같이 쓴맛의 오류를 보아야 합니다.
 
[그림3] 바인딩 구문으로 인한 오류 메시지
 
분명 프로젝트의 참조는 모두 정상적인데 말이죠^^;
 
 
EDM(Entity Data Model) 바인딩 문제 원인
 
우선 EDM(Entity Data Model) 이 웹 프로젝트에 참조되는 형태를 보시면 됩니다.
 
EDM(Entity Data Model) 은 아래와 같이 리소스 형태로 웹 프로젝트에 참조가 됩니다.
 
[그림4] EDM(Entity Data Model) 의 참조 형태
 
잘 모르시겠다구요? 그럼 [그림4] 의 .datasource 를 XML Editor 를 통해 다시 보면 아래와 같이 구성되었습니다.
 
[그림5] EDM(Entity Data Model) 의 .datasource 내용
 
즉, 참조되는 EDM(Entity Data Model) 은 물리적으로 참조되는 어셈블리가 아닌 [그림5] 와 같은 리소스의 형태로도 추가가 됩니다.
 
 
EDM(Entity Data Model) 바인딩 문제 해결 방법
 
그렇다면 이러한 리소스 내용의 타입으로 존재하는 EDM(Entity Data Model) 을 컴파일 할 수 있도록 해야 합니다.
 
웹 프로젝트의 Web.config 에 아래의 내용을 추가해 주어야 합니다.
 
[그림6] EDM 리소스를 컴파일 할 수 있도록 compilation 의 assemblies 요소안에 추가
 
그래야 오류가 없이 웹 페이지가 컴파일 될 수 있습니다.

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

MEF Preview 5 Released  (0) 2009.04.09
[MEF] 4. Import 선언  (6) 2009.04.07
ASP.NET 에서 Entity Framework 바인딩 문제  (2) 2009.03.29
[MEF] 3. Export 선언  (0) 2009.03.29
[MEF] 2. Parts 와 Contracts 선언  (0) 2009.03.22
[MEF] 1. Managed Extensibility Framework 이란?  (0) 2009.03.16
Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 테디 2010.01.08 16:38 Address Modify/Delete Reply

    회사에서 지금 ADO.NET Entity Framework 적용해서 프로젝트 해본경험 있어?

오늘은 비동기 ADO.NET 을 알아볼까 합니다.
아티클을 이해하기 위해서는 비동기 호출에 대한 지식이 약간 필요합니다.
 
우리는 다음과 같은 시간이 오래 걸리는 쿼리를 날릴것입니다.
WAITFOR DELAY '00:00:03'; SELECT * FROM Titles
WAITFOR DELAY '00:00:05'; SELECT * FROM Titles
WAITFOR DELAY '00:00:10'; SELECT * FROM Titles
 
위의 WAITFOR DELAY 는 명령문이 암시하듯 이유없는 대기를 하라는 명령입니다.
3초후에 SELECT, 5초후에 SELECT, 10초후에 SELECT 쿼리를 날려 시간이 오래걸리는 작업을 대체하기 위해서 이지요~
 
다음의 쿼리를 쿼리분석기를 통해 실행시켜 보겠습니다.
 
예상대로 18초가 걸리는군요~
하나하나의 쿼리가 종료해야만이 다음 쿼리를 실행할 수 있죠~
이런방식을 동기 방식이라고 합니다.
C# lock 과 같은 키워드가 여러 개의 쓰레드의 요청이 있더라도, 마치 일렬로 줄을 세워 한번에 하나씩 처리하는 것과 비슷하다고 생각하시면 됩니다.
 
그렇다면, 위의 쿼리를 비동기 방식으로 호출하였을 때 어떤 결과가 나올까요?
그럼, 그 의문을 하나하나씩 풀어보기로 합니다.
 
우선 전체 소스를 보면서 비밀을 하나하나씩 파헤쳐 보겠습니다.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
 
namespace ConsoleTest
{
         class Program
         {
                  // 비동기로연결하기위해Asynchronous Processing 를true 로설정해놓은커넥션Connection String
                  public static string GetConnection
                  {
                           get
                           {
                                   return "Asynchronous Processing=true;server=localhost;database=pubs;uid=sa;password=xxxx";
                           }
                  }
 
                  static void Main(string[] args)
                  {
                           SqlConnection cn1 = new SqlConnection( GetConnection );
                           SqlConnection cn2 = new SqlConnection( GetConnection );
                           SqlConnection cn3 = new SqlConnection( GetConnection );
 
                           SqlCommand cmd1            = new SqlCommand("WAITFOR DELAY '00:00:03'; SELECT * FROM Titles", cn1);
                           SqlCommand cmd2            = new SqlCommand("WAITFOR DELAY '00:00:05'; SELECT * FROM Titles", cn2);
                           SqlCommand cmd3            = new SqlCommand("WAITFOR DELAY '00:00:10'; SELECT * FROM Titles", cn3);
 
                           cn1.Open();
                           cn2.Open();
                           cn3.Open();
 
                           // DataAccess 시작시간을기록한다.
                           DateTime startDate = DateTime.Now;
 
                           // 비동기작업을시작한다.
                           IAsyncResult result1       = cmd1.BeginExecuteReader();
                           IAsyncResult result2       = cmd2.BeginExecuteReader();
                           IAsyncResult result3       = cmd3.BeginExecuteReader();
 
                           WaitHandle[] waitHandle    = new WaitHandle[3];
                           string[] resultStr                 = new string[3];
 
                           waitHandle[0]                      = result1.AsyncWaitHandle;
                           waitHandle[1]                      = result2.AsyncWaitHandle;
                           waitHandle[2]                      = result3.AsyncWaitHandle;
 
                           for (int i = 0; i < waitHandle.Length; i++)
                           {
                               // 배열의핸들이모두신호를받을때까지기다립니다.
                               int endIndex           = WaitHandle.WaitAny( waitHandle, 20000, false );
 
                               switch (endIndex)
                               {
                                   case 0:
                                       cmd1.EndExecuteReader(result1);
                                       resultStr[0]   = DateTime.Now.ToString();
                                       break;
                                   case 1:
                                       cmd2.EndExecuteReader(result2);
                                       resultStr[1]   = DateTime.Now.ToString();
                                       break;
                                   case 2:
                                       cmd3.EndExecuteReader(result3);
                                       resultStr[2]   = DateTime.Now.ToString();
                                       break;
                               }
                           }
 
 
                           cn1.Close();
                           cn2.Close();
                           cn3.Close();
 
                           // DataAccess 작업완료시간을기록한다.
                           DateTime endDate = DateTime.Now;
 
                           for( int i=0; i<resultStr.Length;i++)
                                   Console.WriteLine( " Result {0} : {1}", i, resultStr[i] );
 
 
                           // 두시간의시간차를구하여출력한다.
                           TimeSpan timeSpan = endDate - startDate;
 
                           Console.WriteLine("총작업시간은: {0}", timeSpan.ToString() );
                  }
         }
}
 
 
우선 가장 눈에 띄게 차이 나는 것이 ConnectionString 입니다.
Asynchronous Processing=true;server=localhost;database=pubs;uid=sa;password=xxxx
Asynchronous Processing=true는 비동기로 DataBase 에 연결하기 위해 반드시 추가해 주어야 합니다.
 
또한 비동기 데이터베이스 작업을 하기 위해 SqlCommand 클래스는 세가지의 비동기 메서드가 존재합니다.
대부분의 비동기 메서드들이 Begin 으로 시작하는 네이밍을 갖는 것과 마찬가지로, BeginExecuteNonQuery(), BeginExecuteReader(), BeginExecuteXmlReader()가 바로 그것입니다.
이 메서드는 각각 EndExecuteNonQuery(), EndExecuteReader(), EndExecuteXmlReader() 가 호출됨으로써 비로서 비동기 작업의 콜백을 받을 수 있습니다.
위의 경우는 구현되지 않았지만, DataReader 의 경우 콜백이 완료된 후가 되어야지만 비로서 Read 작업을 수행할 수 있는것입니다. 물론 다른 비동기 메서드로 마찬가지입니다.
 
이 구문은 비동기 ADO.NET 작업의 가장 중요한 부분입니다.
waitHandle[0]                      = result1.AsyncWaitHandle;
waitHandle[1]                      = result2.AsyncWaitHandle;
waitHandle[2]                      = result3.AsyncWaitHandle;
WaitHandle.WaitAny( waitHandle, 20000, false );
 
우리는 waitHandler 배열에 비동기 작업이 끝나는데 사용되는 AsyncWaitHandle 를 넣었습니다.
AsyncWaitHandler 는 비동기 작업이 끝나기를 기다리는 핸들러 입니다.
물론 WaitAny 메서드의 3가지 Overload 는 모두 첫번째 인자를 배열로만 받습니다.
WaitWay 메서드는 우리가 넣은 배열의 요소중에 먼저 끝낸 배열의 Index 를 return 합니다.
waitHandler[2] 의 작업이 제일 먼저 끝나게 되면 배열의 인덱스인 2 를 리턴하게 됩니다.
만약 짧은 시간동안 어느 작업도 끝나지 않게 되면, WaitAny 는 두번째 인자에 적은 시간(밀리초)만큼 무한 대기 하게 됩니다.
 
배열에 개수만큼 루프를 돌면서, 비동기 작업이 끝나는 순서대로 SqlCommand 의 작업을 하게 됩니다.
때문에 결과 화면의 DateTime.Now 의 시간은 각각 달라질 수 있는 것입니다.
 
그럼 실행화면을 보겠습니다.
 
보는대로 총 소요시간은 10초가 되었습니다.
위의 동기작업의 쿼리 수행 결과보다 훨씬~ 빨라졌지요?
각가 쿼리 수행이 완료된 시간도 한번 눈여겨 볼만 하네요~
 
긴 시간이 소요되는 작업이나 여러 번 반복적으로 실행되야 하는 작업등에 적용해 보면 상당히 만족할만할 결과가 아닐 수 없네요~
물론 ASP.NET 의 웹 환경에서도 적용이 가능합니다.
 
그럼 이것으로 오늘 강좌 마칩니다. 뱌뱌 ^^//
Posted by 땡초 POWERUMC

댓글을 달아 주세요