블로그 이미지
* Microsoft MVP - Windows Development 2014 ~ 2020 http://youtube.com/FutureOfDotNet kaki104

카테고리

List All (613)
Uno Platform (2)
Visual Studio (6)
Blazor (2)
Windows App(Universa.. (106)
Xamarin Forms (4)
Bot Framework (19)
Azure (10)
Windows 10 (53)
WPF (7)
Facebook News & Tips (158)
Windows 8&8.1 (113)
Windows Phone 8 (42)
Silverlight (37)
HTML5 & MVC4 (16)
Portable Class Library (2)
Uncategorised Tips a.. (3)
Kinect for Windows (2)
ETC (12)
kaki104 Scrap (4)
App News (13)
Total553,920
Today5
Yesterday46

일단 디자인 레이아웃은..실버라이트 코리아의 디자인을 빼꼈다는..쿨럭 ^^;;;;;디자인 해줄 분이 없는 관계로..ㅜㅜ 그냥 기본 디자인만 잡아 봤고, 이제 슬슬 본격 적으로 사용해야할 폴더들을 만들어 놓고, 리소스딕셔너리도 추가해 놓구 ㅎㅎ

1. 기본 메인 디자인

디자인 정말 거시기한.. 다시 한번 디자인 해주실 구해야 겠다는..손좀 들어보시죠??(ㅡㅡ+) 이것이 통짜 실버라이트 게시판...이 될 예정인 화면! 냐하하..음음..이 소스는..덩치가 큰 관계로 일부 파일만 첨부를 해서 올리도록 하겠다..(머 소스 업어두 아무도 신경쓰지 앙치만..ㅜㅜ 나랑 같이 만들고 있는 사람 손좀;;)

2. 중요 부분

2-1. 폴더 추가
SL5_BOARD 프로젝
-> Images, Models, Resources, ViewModels, Views

2-2. 일단 기존에 있던 내용들은 싹다 지우고 새로 그린 것이고, 이렇게 디자인을 할때 블랜드를 사용하지 앙고 디자인 하면 무지 스트레스 받으니, 미리미리 블랜드 사용법도 익혀 두는 것이 정신 건강에 도움이 된다는..

2-3. 이미지는 뷰박스로 싸메서 사용한다. 그래야 이미지 크기가 변경대구 하더라도 보기 좋다.

<Viewbox Stretch="Fill" Grid.Row="1" Margin="6,0">
 <Image x:Name="ImgLogo" Source="Images/logoPixelImage.jpg" Stretch="None"/>
</Viewbox>

참, 여기서...프로젝트에 이미지를 포함하고 불러다가 사용할 때.. 이미지 파일의 속성에 들어가서 Build Action을 꼭 Resource로 지정하고 불러다가 사용해야한다. 음음..이거 몰라서 몇 시간 허비하면 눈물난다..

2-4. 동일한 스타일이나, 컬러등은 리소스로 만들어서 사용한다. 이 리소스 만드는 작업이 블랜드를 사용하면 메뉴 하나 클릭하면 바로 만들어 지지만 VS2010에서는 일일이 수작업으로 만들어야 한다.

* 수동 작업 방법
Resources폴더에서 Add -> New Item -> Resources File 추가

BoardResourceDictionary.xaml

 <ResourceDictionary
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 <SolidColorBrush x:Key="CountColor" Color="#FFFF1E1E"/>
 <!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>


 App.xaml

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="SL5_BOARD.App"
             >
    <Application.Resources>
       
     <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
       <ResourceDictionary Source="Resources/BoardResourceDictionary.xaml"/>
      </ResourceDictionary.MergedDictionaries>
     </ResourceDictionary>
       
    </Application.Resources>
</Application>


이렇게 만들어 놓으면 어떤 화면이서든지 리소스를 xaml에 바로 적용할 수 있다.

<StackPanel Margin="4,0" Orientation="Horizontal">
 <TextBlock TextWrapping="Wrap" Text="게시물" FontSize="12" Width="40"/>
 <TextBlock TextWrapping="Wrap" Text="44" FontSize="12" FontWeight="Bold" Margin="5,0,0,0" Foreground="{StaticResource CountColor}"/>
</StackPanel>

2-5. 디자인 하면서 까다로운 작업 중 하나가.. 스크롤 관련 문제이다..이 화면도 메뉴 부분을 스크롤 시키기 위해서 약간 시간이 걸렸는데.. 머리를 열심히 굴려야 왜 저렇게 해야하는지 이해가 된다..이걸 VS2010에서만 작업해서 만들려고 하면 ...머리에서 쥐가..쿨럭..

<Border x:Name="MainMenu" BorderBrush="#FFAED8DC" BorderThickness="4" Grid.Row="1" Margin="0,8,0,0" CornerRadius="10" Padding="6">
 <ScrollViewer BorderThickness="0">
  <StackPanel Margin="0">
   <ListBox BorderThickness="0">
    <ListBoxItem Content="전체글보기" BorderThickness="0"/>
    <ListBoxItem Content="카페태그보기"/>
    <ListBoxItem Content="베스트게시물"/>
    <ListBoxItem Content="소셜앱"/>
    <ListBoxItem Content="공지/수요소식"/>
    <ListBoxItem Content="매일매일 출석~"/>
    <ListBoxItem Content="자기소개~"/>
    <ListBoxItem Content="자유로운글"/>
    <ListBoxItem Content="멋쟁이 사진첩"/>
    <ListBoxItem Content="자유사진첩"/>
    <ListBoxItem Content="세미나/행사/자료"/>
    <ListBoxItem Content="회원작품"/>
    <ListBoxItem Content="RIA 구현 사례"/>
    <ListBoxItem Content="구인/구직"/>
    <ListBoxItem Content="운영자카페"/>
    <ListBoxItem Content="운영자게시판"/>
    <ListBoxItem Content="실버라이트"/>
    <ListBoxItem Content="강좌"/>
    <ListBoxItem Content="Tips And Tricks"/>
   </ListBox>
  </StackPanel>
 </ScrollViewer>
</Border>

2-6. 메인 컨텐츠가 들어갈 부분은 ItemsControl로 작업 했다. 그곳에 다른 곳에서 만들어 놓은 UserControl을 계속 번갈아 가며 올릴 것이다. 음..이것 말고 Page를 쓸까 생각해 봤는데..Page를 사용했을 때 네비게이션 기능 말고는..별로 없는 것 같아서..이번에는 이걸로 하기로 했다.


3. 디자인이 되니 뭔가 보이는 것 같다. 빨리 진행해서 이번주 안에 1차 완성을 할 수 있었으면 한다. 그리고...디자인 해줄 분 다시 한번 구한당..ㅜㅜ

 ****첨부 파일은 SL5_BOARD 프로젝트만 포함되었다..전체 소스가 아니니 실행은 앙된다..^^;;; 전체 소스가 필요한 사람은 리플로 요청을 하면 개별 적으로 보내 주는 것으로....하지만 본인이 직접 만들어 봐야 실력이 늘어나니..열심히 화이팅~

Posted by MVP kaki104

댓글을 달아 주세요

이젠 나머지 테이블들 만들고 본격 적으로 들어가야 겠다. 다른 테이블들 만드는 것은 어렵지 앙았는데.. 한가지 문제 해결과 한가지 문제가 생겼다..


1. 나머지 테이블들
(작업 하면서 테이블 명세서를 약간씩 수정했는데..테이블 명세서만 필요하지는 않을 것 같아..첨부파일로 올리지는 앙는다)

BOARD_REPLY.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace SL5_BOARD.Web.Model
{
    public class BOARD_REPLY
    {
        [Key]
        public int BOARD_REPLY_IDX { get; set; }
        public string REPLY_CONTENT { get; set; }
        public DateTime REG_DT { get; set; }
        public int REG_IDX { get; set; }
        public DateTime? UPT_DT { get; set; }
        public int? UPT_IDX { get; set; }

        public virtual BOARD_LIST BoardList { get; set; }
        public int BOARD_LIST_IDX { get; set; }
    }
}


BOARD_ATTACH.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace SL5_BOARD.Web.Model
{
    public class BOARD_ATTACH
    {
        [Key]
        public int BOARD_ATTACH_IDX { get; set; }
        public string FILE_NAME { get; set; }
        public string FILE_EXT { get; set; }
        public int FILE_SIZE { get; set; }
        public DateTime REG_DT { get; set; }
        public int REG_IDX { get; set; }
        public DateTime? UPT_DT { get; set; }
        public int? UPT_IDX { get; set; }

        public virtual BOARD_LIST BoardList { get; set; }
        public int BOARD_LIST_IDX { get; set; }

        public BOARD_ATTACH()
        {
            FILE_SIZE = 0;
        }
    }
}


MST_MEMBER.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace SL5_BOARD.Web.Model
{
    public class MST_MEMBER
    {
        [Key]
        public int MST_MEMBER_IDX { get; set; }
        public string EMAIL { get; set; }
        public string PASSWORD { get; set; }
        public string MEMBER_NAME { get; set; }
        public string NICK_NAME { get; set; }
        public bool EMAIL_RECEIVE { get; set; }
        public string DESCRIPTION { get; set; }
        public DateTime LAST_LOGIN_DT { get; set; }
        public string JOB { get; set; }
        public string HOBBY { get; set; }
        public string INTEREST { get; set; }
        public int MEMBER_SCORE { get; set; }
        public string MEMBER_GRADE { get; set; }
        public string ETC { get; set; }
        public int STATUS { get; set; }
        public DateTime REG_DT { get; set; }
        public int REG_IDX { get; set; }
        public DateTime? UPT_DT { get; set; }
        public int? UPT_IDX { get; set; }

        public MST_MEMBER()
        {
            EMAIL_RECEIVE = true;
            LAST_LOGIN_DT = DateTime.Parse("2000-01-01");
            MEMBER_SCORE = 0;
            STATUS = 0;
        }
    }
}


SL5_BOARD_DBCONTEXT.cs 전체 소스


using System.Data.Entity;
using System.Web;

namespace SL5_BOARD.Web.Model
{
    public class SL5_BOARD_DBCONTEXT : DbContext
    {
        public SL5_BOARD_DBCONTEXT()
            : base("SL5_BOARD")
        {
            if (HttpContext.Current == null)
            {
                //맨뒤에 새로 추가된 부분이 데이터베이스가 변경되었을 때 db를 새로 만든다..라는..머 그런 내용
                Database.SetInitializer<SL5_BOARD_DBCONTEXT>(new SL5_BOARD_DBCONTEXTInitializer());
            }
        }

        public DbSet<BOARD_MAIN> BOARD_MAINS { get; set; }
        public DbSet<BOARD_LIST> BOARD_LISTS { get; set; }
        public DbSet<BOARD_REPLY> BOARD_REPLYS { get; set; }
        public DbSet<BOARD_ATTACH> BOARD_ATTACHS { get; set; }
        public DbSet<MST_MEMBER> MST_MEMBERS { get; set; }
    }

    //내부에는 Seed라고 해서 새로운 DB가 만들어지면 내용을 넣도록 되어있는데..그런건 뺐음
    //이곳이 실행되면서 db를 새로 만들어줌..(그러나..100% 잘 동작되는 것은 아님)
    public class SL5_BOARD_DBCONTEXTInitializer : DropCreateDatabaseIfModelChanges<SL5_BOARD_DBCONTEXT>
    {
    }
}

2. 한가지 문제 해결
위에 내용이 있는데..데이터베이스가 변경되었을 때 수동으로 삭제하고 다시 만들어야 했던 부분이 해결되었다. 음..사용해 본 봐에 의하면 한 90%정도는 지워지고 다시 잘 만들어지는데 10%정도는 앙대는 경우도 있으니 그때는 삭제하고 실행하면 다시 만들어 준다..하하하..(Compact DB이니 삭제하고 만들고 삭제하고 만들고 하는 부분에 대해 이해를 해보도록 하자;;)

3. 한가지 문제 발생
각 테이블에는 REG_ID, UPT_ID라는 필드가 존재하는데..이것이..MST_MEMBER 테이블과 연결이 되어야 하는 필드들이다. 그런데 동일한 테이블들끼리 1:N 연결관계를 2개를 만들어 줘야하는데..그게 쉽지 않다...그래서, 찾아보다가.. 고수들의 도움을 받기위해 MS 포럼에 질문을 올려 놓은 상태이니 좀 기다리면..답변이 달리지 앙을까 한다..(끝까지 앙달리면 다른 방법을..쿨럭)

4. 이번은 여기서
마무리 하고 다음은 SL5_BOARD 프로젝트의 전체 적인 설계 방향을 잡아보도록 하자.

Posted by MVP kaki104

댓글을 달아 주세요

처음에 Streamlined Operation의 맛을 보았을 때 황당했었는데.. 마치 유주얼서스팩트의 마지막을 보는 듯한..느낌이였죠, 그런데, 그걸 글로 표현해서 보여줄려면 어떻게 해야 할까..고민하다가 제목의 주제로 추가 작성을 하기로 했다.


1. 서버사이드 기술과 클라이언트 사이드 기술
정리를 하고 시작해 보자.

1-1. SL5_BOARD.Web 프로젝트에서 사용되는 기술
: SQL Server Compact 4.0 + Entity Framework 4.1 (Streamlined Database)
: 서버단에서는 SL5_BOARD_DBCONTEXT를 통해 모든 데이터를 관리, 그렇기 때문에 LINQ쿼리를 통해서 마음대로 불러내고 저장하고 떡주무르듯 할 수 있음

1-2. SL5_BOARD 프로젝트에서 사용되는 기술
: WCF RIA Service Support EF4.1
: 서버에 있는 데이터를 일단은 클라이언트까지 전송하는 기능, 전송된 데이터를 관리하는 기능, 하지만, 역시 데이터가 서버에 존재 하기 때문에 클라이언트까지 가지고 오는 것이 선행되어야 함


2. 짐승같은 코딩과 인간같은 코딩

위의 둘은 요렇게 서로 연결이 되어있다..(이렇게 연결시키기 위해서 열심히 이것 저것 했으니..되어야징..) 그런데 연결을 왜 해 놓은걸까? 방금 전 소스상에서 연결해 놓은 덕을 보았나? 그렇게 할려면 뭐한다고 연결하는 것인가? 음음음...그러게..여태까지 짐승같은 코딩을 해 놓은 거내~~~~~~~~~~~~~이제 짐승코딩에서 인간코딩으로 바꿔보자..그래서 인간이 되어야 인간답게 살 수 있는 거다.


2-2. 짐승같은 코딩
BOARD_MAIN에 셀렉트 채인지 이벤트 발생시마다, 해당 데이터를 조해서 다시 뿌려주는..코딩

//그리드 셀렉션 체인지 이벤트 처리
private void bOARD_MAINDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    //컨테이너에 데이터가 존재 한다면
    if (dsContext.EntityContainer != null)
    {
        //리스트의 내용을 지워놓고
        dsContext.BOARD_LISTs.Clear();
        //선택된 BOARD_MAIN을 일단 넣궁
        BOARD_MAIN bm = e.AddedItems.Cast<BOARD_MAIN>().FirstOrDefault();

        //BOARD_MAIN에 속해있는 BOARD_LIST만 조회
        dsContext.Load(dsContext.GetBoardListByBoardMainQuery(bm.BOARD_MAIN_IDX), LoadBehavior.RefreshCurrent, true);
    }
}

2-3. 인간같은 코딩
: 딱 필요할 때만 데이터를 서버에서 불러오고, 그 외에는 자체 해결~

수정 포인트 1

MainPage.xaml.cs

private void bOARD_MAINDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

    //선택된 BOARD_MAIN을 넣구
    BOARD_MAIN bm = e.AddedItems.Cast<BOARD_MAIN>().FirstOrDefault();

    //BOARD_MAIN에 속해있는 BOARD_LIST의 카운트가 0이거나, BOARD_MAIN이 변경되었을 경우
    if (bm.BoardLists.Count == 0 || bm.HasChanges == true)
    {

        //BOARD_MAIN_IDX가 들어있는 BOARD_LIST 조회
        dsContext.Load(dsContext.GetBoardListByBoardMainQuery(bm.BOARD_MAIN_IDX), LoadBehavior.RefreshCurrent, true);
    }
}


수정 포인트 2

MainPage.xaml

<sdk:DataGrid AutoGenerateColumns="False" Grid.Row="3"
              ItemsSource="{Binding SelectedItem.BoardLists, ElementName=bOARD_MAINDataGrid}"
              Name="bOARD_LISTDataGrid"
              RowDetailsVisibilityMode="VisibleWhenSelected">

바인딩 항목이 바뀌었다. 전에는 ItemsSource="{Binding Path=BOARD_LISTs}" 라는 항목을 바인딩 했었지만 지금은 BOARD_MAIN이 표시되는 그리드의 선택된 내용에 있는 BoardLists라는 항목을 바인딩 한다. 무슨 차이가 있을까??

지금부터 5분간 머리속으로 상상을 해보기 바란다. 그 차이를 찾는다면 왜 이게 인간같은 코딩인지 알 수 있을 것이다.


2. 열심히 로딩과 게으른 로딩(Eagerly loading and Lazy loading)
위와 같은 인간같은 코딩의 기본에는 열심히 로딩과 게으른 로딩(명시적 로딩과 비명시적 로딩 혹은 동기, 비동기 로딩)이란 베이스 기술이 필요하다.

Using DbContext in EF 4.1 Part 6: Loading Related Entities

http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx

BOARD_MAIN은 이미 BOARD_LIST 중 어떤 넘이 자신을 찍었는지 알고 있다..다만 어떤 넘인지 표현 하려면, BOARD_LIST가 로딩이 되어야 가능하고, 로딩하는 시간과 방법에 따라 2가지로 구분을 한것이다. 좀 더 자세히 살펴 보면, BOARD_MAIN.cs 파일을 보면 아래와 같은 내용이 있었는데..

public virtual ObservableCollection<BOARD_LIST> BoardLists { get; set; }

여기서 virtual을 사용해준것이 게으른 로딩 방식을 사용하겠다는 뜻이다. 즉, 처음에 로딩할때 데이터 없이 그냥 로딩이 된다 하더라도, 나중에 데이터가 Context로 로딩이 되어 들어온다면 그 때 바인딩을 하겠다는 것이다.

3. 결과는 4회차 강좌나 5회차 강좌나 동일하다.
하지만, 그 내용적인 측면에서는 큰 의미를 가지고 있이며, 그걸 가지고 가기를 원한다. MS사의 개발 철학은 Decouple, Asynchronous, Loosely, Lazy 로 이동 중이며, Windows 8이 발표 되면서 정점을 찍을 것으로 생각된다.

Posted by MVP kaki104

댓글을 달아 주세요

이번에는 하나의 테이블을 추가해서 두개의 테이블을 서로 연결 시켜 놓고, CRUD를 하는 방법에 대해서 설명한다.

참고적으로.. 지금 개발하는 Silverlight 5, WCF RIA Service Support EF 4.1, SQL Server Compact 4.0을 이용한 예제 프로그램은 전세계에서 아마 이 프로그램이 유일할 듯하다.. 유사 프로그램도 없어서 하나 하나 찾아서 만드는게 쉽지 않다..그러나.. 끝까지 완성해서 실버라이트 공개 게시판이 자유롭게 만들어 지도록 하겠다...언넝 만들어야징;;(혼자 만들면 심심한데..ㅜㅜ 리플로 놀아주면 좋겠다는..쿨럭)

 
1. BOARD_LIST 테이블 추가

SL5_BOARD.Web -> Model Folder -> BOARD_LIST.cs 파일 추가

 using System;
using System.ComponentModel.DataAnnotations;

namespace SL5_BOARD.Web.Model
{
    public class BOARD_LIST
    {
        [Key]
        public int BOARD_LIST_IDX { get; set; }
        public string LIST_TITLE { get; set; }
        public string LIST_CONTENT { get; set; }
        public bool LIST_ATTACH_YN { get; set; }
        public int LIST_SEQ { get; set; }
        public int LIST_LEVEL { get; set; }
        public int LIST_VIEW_COUNT { get; set; }
        public string LIST_WRITER_NAME { get; set; }
        [DataType(DataType.Password)]  //패스워드를 저장할때 어떻게좀 해볼려고 써봤는데..잘 앙됨
        public string LIST_PASSWORD { get; set; }
        public string LIST_KIND { get; set; }
        public int LIST_COMPLETE_GB { get; set; }
        public bool LIST_OPEN_YN { get; set; }
        public int LIST_GOOD_COUNT { get; set; }
        public int LIST_PUBLIC_GB { get; set; }
        public DateTime REG_DT { get; set; }
        public int REG_IDX { get; set; }
        public DateTime? UPT_DT { get; set; }
        public int? UPT_IDX { get; set; }

        //여기가 중요!!
        //BOARD_MAIN 테이블과 연결 고리 음 일명 뽀링키가 되는데 형태가 오브젝트다
        //그리고 진짜 키 값은 바로 아래 필드에 존재하는데..사용 방법은 나중에

        public virtual BOARD_MAIN BoardMain { get; set; }
        public int BOARD_MAIN_IDX { get; set; }

        //생성자에서 초기값을 넣어 준다..귀찮으니 여기서 한번만 지정해 놓는다..int, bool형은 꼭 있어야 하더라는
        //이렇게 하는 것이 싫으면 위에 필드 타입에 ?를 붙여 주면 된다.

        public BOARD_LIST()
        {
            LIST_ATTACH_YN = false;
            LIST_SEQ = 0;
            LIST_LEVEL = 1;
            LIST_VIEW_COUNT = 0;
            LIST_COMPLETE_GB = 0;
            LIST_OPEN_YN = true;
            LIST_GOOD_COUNT = 0;
            LIST_PUBLIC_GB = 0;
        }
    }
}

2. BOARD_MAIN 테이블 수정

using System;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;

namespace SL5_BOARD.Web.Model
{
    public class BOARD_MAIN
    {
        [Key]
        public int BOARD_MAIN_IDX { get; set; }
        public string BOARD_NAME { get; set; }
        public string BOARD_TYPE { get; set; }
        public bool MEMBER_CHECK { get; set; }
        public string BOARD_DESC { get; set; }
        public string BOARD_STATE { get; set; }
        public DateTime REG_DT { get; set; }
        public int REG_IDX { get; set; }
        public DateTime? UPT_DT { get; set; }
        public int? UPT_IDX { get; set; }

        //BOARD_MAIN은 여러개의 BOARD_LIST를 가질 수 있다. 그래서 그런 연결관계에 대해서 메인에도 표시를
        //해주어야 한다. 역시 여기서도 옵저블컬렉션을 사용해서 세트를 만들었다.

        public virtual ObservableCollection<BOARD_LIST> BoardLists { get; set; }

        //BOARD_MAIN의 생성자
        public BOARD_MAIN()
        {
            BOARD_NAME = "신규 게시판";
            MEMBER_CHECK = false;
            //생성자에서 리스트 인스턴스 시켜준다.
            this.BoardLists = new ObservableCollection<BOARD_LIST>();
        }
    }
}

3. SL5_BOARD_DBCONTEXT 수정

using System.Data.Entity;
using System.Web;

namespace SL5_BOARD.Web.Model
{
    public class SL5_BOARD_DBCONTEXT : DbContext
    {
        public SL5_BOARD_DBCONTEXT()
            : base("SL5_BOARD")
        {
            if (HttpContext.Current == null)
            {
                Database.SetInitializer<SL5_BOARD_DBCONTEXT>(null);
            }
        }

        public DbSet<BOARD_MAIN> BOARD_MAINS { get; set; }

        //이넘 하나만 추가하면 된다.
        public DbSet<BOARD_LIST> BOARD_LISTS { get; set; }
    }
}

4. F6을 눌러서 빌드해 본다.

아마 100% 에러 날것이다.. 에..그 이유는 데이터 베이스에 내용이 변경되면 새로 만들어 주는 명령이 있는데..그 명령 EF4.1 버전에서 어떻게 사용하는지를 찾다가 포기했기 때문이다..ㅜㅜ 그래서 일단은 데이터베이스에 변경사항이 있을 경우 DB를 지워줘야 한다.(물론 수동이다..^^;;) 그래서 프로젝 끝나기 전까지는 웬만하면 데이터 마니 앙넣을려고 한다;;

SL5_BOARD.Web 프로젝트에 App_Data 폴더에 가서 SL5_BOARD.sdf 파일을 지우고 다시 F6을 눌러준다. 정상 적으로 빌드가 되었다면 다음으로 넘어간다.


5. SL5_BOARDDomainService.cs 파일 수정

#region BOARD_LIST
//기본적으로 전체 호출 하는 넘

public IQueryable<BOARD_LIST> GetBoardList()
{
    return this.DbContext.BOARD_LISTS;
}

//BOARD_MAIN_IDX 값을 받아서 조건에 만족하는 데이터만 반환, 참고로 LINQ 공부도 병행해야 한다..
public IQueryable<BOARD_LIST> GetBoardListByBoardMain(int BoardMainIDX)
{
    var query = from p in this.DbContext.BOARD_LISTS
                where p.BOARD_MAIN_IDX == BoardMainIDX
                orderby p.BOARD_LIST_IDX descending
                select p;

    return query.AsQueryable();
}

public void InsertBoardList(BOARD_LIST entity)
{
    DbEntityEntry<BOARD_LIST> entityEntry = this.DbContext.Entry(entity);
    if ((entityEntry.State != EntityState.Detached))
    {
        entityEntry.State = EntityState.Added;
    }
    else
    {
        this.DbContext.BOARD_LISTS.Add(entity);
    }
}

public void UpdateBoardList(BOARD_LIST entity)
{
    this.DbContext.BOARD_LISTS.AttachAsModified(entity, this.ChangeSet.GetOriginal(entity), this.DbContext);
}

public void DeleteBoardList(BOARD_LIST entity)
{
    DbEntityEntry<BOARD_LIST> entityEntry = this.DbContext.Entry(entity);
    if ((entityEntry.State != EntityState.Deleted))
    {
        entityEntry.State = EntityState.Deleted;
    }
    else
    {
        this.DbContext.BOARD_LISTS.Attach(entity);
        this.DbContext.BOARD_LISTS.Remove(entity);
    }
}
#endregion

수정 후 F6눌러서 컴파일을 꼭 해준다.


6. SL5_BOARD 프로젝트로 넘어간다.

MainPage.xaml의 디자인을 변경한다.



화면 구성은 대충 이정도 쯤인데.. 화면 구성만 바뀐것이 아니라 내부에 xaml단의 코딩이 변경되었다.

중요 변경사항은..riacontrol을 삭제, 그리드가 LayoutRoot의 DataContext에 있는 데이터를 바인딩 하도록 변경 되었다.

MainPage.xaml의 전체 소스다. 일단 지금은 타이틀리 커플드로 작업하고 차 후에 MVVM모델로 변경한다.

<UserControl x:Class="SL5_BOARD.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:my="clr-namespace:SL5_BOARD.Web.Model"
    xmlns:my1="clr-namespace:SL5_BOARD.Web.DomainService"
    d:DesignHeight="300" d:DesignWidth="400" Loaded="UserControl_Loaded">

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="94*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="148*" />
        </Grid.RowDefinitions>
       
        <sdk:DataGrid AutoGenerateColumns="False"
                      ItemsSource="{Binding Path=BOARD_MAINs}"
                      Name="bOARD_MAINDataGrid"
                      RowDetailsVisibilityMode="VisibleWhenSelected"
                      Grid.Row="1" SelectionChanged="bOARD_MAINDataGrid_SelectionChanged">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn x:Name="bOARD_MAIN_IDXColumn" Binding="{Binding Path=BOARD_MAIN_IDX, Mode=OneWay}" Header="BOARD MAIN IDX" IsReadOnly="True" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="bOARD_NAMEColumn" Binding="{Binding Path=BOARD_NAME}" Header="BOARD NAME" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="bOARD_TYPEColumn" Binding="{Binding Path=BOARD_TYPE}" Header="BOARD TYPE" Width="SizeToHeader" />
                <sdk:DataGridCheckBoxColumn x:Name="mEMBER_CHECKColumn" Binding="{Binding Path=MEMBER_CHECK}" Header="MEMBER CHECK" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="bOARD_DESCColumn" Binding="{Binding Path=BOARD_DESC}" Header="BOARD DESC" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="bOARD_STATEColumn" Binding="{Binding Path=BOARD_STATE}" Header="BOARD STATE" Width="SizeToHeader" />
                <sdk:DataGridTemplateColumn x:Name="rEG_DTColumn" Header="REG DT" Width="SizeToHeader">
                    <sdk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <sdk:DatePicker SelectedDate="{Binding Path=REG_DT, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellEditingTemplate>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=REG_DT, StringFormat=\{0:d\}}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>

                <sdk:DataGridTextColumn x:Name="rEG_IDXColumn" Binding="{Binding Path=REG_IDX}" Header="REG IDX" Width="SizeToHeader" />
                <sdk:DataGridTemplateColumn x:Name="uPT_DTColumn" Header="UPT DT" Width="SizeToHeader">
                    <sdk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <sdk:DatePicker SelectedDate="{Binding Path=UPT_DT, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellEditingTemplate>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=UPT_DT, StringFormat=\{0:d\}}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
                <sdk:DataGridTextColumn x:Name="uPT_IDXColumn" Binding="{Binding Path=UPT_IDX}" Header="UPT IDX" Width="SizeToHeader" />
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
        <Button Content="Insert" Height="23" HorizontalAlignment="Left" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" Margin="97,0,0,0" />
        <Button Content="Update" Height="23" HorizontalAlignment="Left" Margin="178,0,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
        <Button Content="Delete" Height="23" HorizontalAlignment="Left" Margin="259,0,0,0" Name="button3" VerticalAlignment="Top" Width="75" Click="button1_Click"/>

        <sdk:DataGrid AutoGenerateColumns="False" Grid.Row="3"
                      ItemsSource="{Binding Path=BOARD_LISTs}"
                      Name="bOARD_LISTDataGrid"
                      RowDetailsVisibilityMode="VisibleWhenSelected">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn x:Name="bOARD_LIST_IDXColumn" Binding="{Binding Path=BOARD_LIST_IDX, Mode=OneWay}" Header="BOARD LIST IDX" IsReadOnly="True" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="bOARD_MAIN_IDXColumn1" Binding="{Binding Path=BOARD_MAIN_IDX}" Header="BOARD MAIN IDX" Width="SizeToHeader" />
                <sdk:DataGridCheckBoxColumn x:Name="lIST_ATTACH_YNColumn" Binding="{Binding Path=LIST_ATTACH_YN}" Header="LIST ATTACH YN" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_COMPLETE_GBColumn" Binding="{Binding Path=LIST_COMPLETE_GB}" Header="LIST COMPLETE GB" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_CONTENTColumn" Binding="{Binding Path=LIST_CONTENT}" Header="LIST CONTENT" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_GOOD_COUNTColumn" Binding="{Binding Path=LIST_GOOD_COUNT}" Header="LIST GOOD COUNT" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_KINDColumn" Binding="{Binding Path=LIST_KIND}" Header="LIST KIND" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_LEVELColumn" Binding="{Binding Path=LIST_LEVEL}" Header="LIST LEVEL" Width="SizeToHeader" />
                <sdk:DataGridCheckBoxColumn x:Name="lIST_OPEN_YNColumn" Binding="{Binding Path=LIST_OPEN_YN}" Header="LIST OPEN YN" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_PASSWORDColumn" Binding="{Binding Path=LIST_PASSWORD}" Header="LIST PASSWORD" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_PUBLIC_GBColumn" Binding="{Binding Path=LIST_PUBLIC_GB}" Header="LIST PUBLIC GB" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_SEQColumn" Binding="{Binding Path=LIST_SEQ}" Header="LIST SEQ" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_TITLEColumn" Binding="{Binding Path=LIST_TITLE}" Header="LIST TITLE" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_VIEW_COUNTColumn" Binding="{Binding Path=LIST_VIEW_COUNT}" Header="LIST VIEW COUNT" Width="SizeToHeader" />
                <sdk:DataGridTextColumn x:Name="lIST_WRITER_NAMEColumn" Binding="{Binding Path=LIST_WRITER_NAME}" Header="LIST WRITER NAME" Width="SizeToHeader" />
                <sdk:DataGridTemplateColumn x:Name="rEG_DTColumn1" Header="REG DT" Width="SizeToHeader">
                    <sdk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <sdk:DatePicker SelectedDate="{Binding Path=REG_DT, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellEditingTemplate>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=REG_DT, StringFormat=\{0:d\}}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
                <sdk:DataGridTextColumn x:Name="rEG_IDXColumn1" Binding="{Binding Path=REG_IDX}" Header="REG IDX" Width="SizeToHeader" />
                <sdk:DataGridTemplateColumn x:Name="uPT_DTColumn1" Header="UPT DT" Width="SizeToHeader">
                    <sdk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <sdk:DatePicker SelectedDate="{Binding Path=UPT_DT, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellEditingTemplate>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=UPT_DT, StringFormat=\{0:d\}}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
                <sdk:DataGridTextColumn x:Name="uPT_IDXColumn1" Binding="{Binding Path=UPT_IDX}" Header="UPT IDX" Width="SizeToHeader" />
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
        <TextBlock HorizontalAlignment="Left" Name="textBlock1" Text="BOARD MAIN :" VerticalAlignment="Center" Margin="8,4,0,3" />
        <Button Content="Insert List" Height="23" HorizontalAlignment="Left" Margin="97,6,0,0" Name="button4" VerticalAlignment="Top" Width="75" Grid.Row="2" Click="button4_Click" />
        <Button Content="Update List" Height="23" HorizontalAlignment="Left" Margin="178,6,0,0" Name="button5" VerticalAlignment="Top" Width="75" Grid.Row="2"  Click="button4_Click"/>
        <Button Content="Delete List" Height="23" HorizontalAlignment="Left" Margin="259,6,0,0" Name="button6" VerticalAlignment="Top" Width="75" Grid.Row="2"  Click="button4_Click"/>
        <TextBlock HorizontalAlignment="Left" Margin="8,10,0,9" Name="textBlock2" Text="BOARD LIST :" VerticalAlignment="Center" Grid.Row="2" />
    </Grid>
</UserControl>


7. MainPage.xaml.cs 전체

using System;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using System.Windows.Controls;
using SL5_BOARD.Web.DomainService;
using SL5_BOARD.Web.Model;

namespace SL5_BOARD
{
    public partial class MainPage : UserControl
    {
        //도메인 서비스를 사용하기 위한 변수 선언
        SL5_BOARDDomainContext dsContext;
        
        public MainPage()
        {
            InitializeComponent();

            //도메인 서비스 인스턴스
            dsContext = new SL5_BOARDDomainContext();
            //LayoutRoot.DataContext에 바인딩..이렇게 하면 하위 컨트롤들의 DataContext에도 모두 함께 바인딩 됨
            LayoutRoot.DataContext = dsContext;
        }

        //BOARD_MAIN INSERT, UPDATE, DELETE
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            switch (btn.Content.ToString())
            {
                case "Insert":
                    //riacontrol을 빼고 심플하게 정리
                    BOARD_MAIN bm = new BOARD_MAIN();
                    bm.REG_DT = DateTime.Now;
                    bm.REG_IDX = -1;
                    dsContext.BOARD_MAINs.Add(bm);
                    dsContext.SubmitChanges();
                    break;
                case "Update":
                    dsContext.SubmitChanges();
                    break;
                case "Delete":
                    //그리드에 선택된 내용 확인
                    if ((bOARD_MAINDataGrid.SelectedItem as BOARD_MAIN) != null)
                    {
                        dsContext.BOARD_MAINs.Remove(bOARD_MAINDataGrid.SelectedItem as BOARD_MAIN);
                        dsContext.SubmitChanges();
                    }
                    break;
            }
        }

        //BOARD_LIST INSERT, UPDATE, DELETE
        private void button4_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            switch (btn.Content.ToString())
            {
                case "Insert List":
                    if ((bOARD_MAINDataGrid.SelectedItem as BOARD_MAIN) != null)
                    {
                        BOARD_LIST bl = new BOARD_LIST();
                        dsContext.BOARD_LISTs.Add(bl);
                        bl.REG_DT = DateTime.Now;
                        bl.REG_IDX = -1;

                        //선택된 BOARD_MAIN을 여기다가 쑤셔 넣은 후 저장
                        bl.BoardMain = bOARD_MAINDataGrid.SelectedItem as BOARD_MAIN;

                        dsContext.SubmitChanges();
                    }
                    break;
                case "Update List":
                    dsContext.SubmitChanges();
                    break;
                case "Delete List":
                    if (bOARD_LISTDataGrid.SelectedItem as BOARD_LIST != null)
                    {
                        dsContext.BOARD_LISTs.Remove(bOARD_LISTDataGrid.SelectedItem as BOARD_LIST);
                        dsContext.SubmitChanges();
                    }
                    break;
            }
        }

        //화면 로딩 후 BOARD_MAIN 전체 조회
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            dsContext.Load(dsContext.GetBoardMainQuery(), LoadBehavior.RefreshCurrent, true);
        }

        //그리드 셀렉션 체인지 이벤트 처리
        private void bOARD_MAINDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //컨테이너에 데이터가 존재 한다면
            if (dsContext.EntityContainer != null)
            {
                //리스트의 내용을 지워놓고
                dsContext.BOARD_LISTs.Clear();
                //선택된 BOARD_MAIN을 일단 넣궁
                BOARD_MAIN bm = e.AddedItems.Cast<BOARD_MAIN>().FirstOrDefault();
                //BOARD_MAIN에 속해있는 BOARD_LIST만 조회
                dsContext.Load(dsContext.GetBoardListByBoardMainQuery(bm.BOARD_MAIN_IDX), LoadBehavior.RefreshCurrent, true);
            }
        }
    }
}


8. 실행 모습



음..물론 Update, Delete 기능도 잘 동작한다.


9. 나머지 테이블도...
 후딱 만들고 본격적으로 작업에 들어가야 겠다..그런데 역시 Code First라 테이블 만들기가 매우 귀찮은..쿨럭..그냥 Model First에서 모델만들고 한번에 후루룩 만들면 더 쉬울건데..

전체 길이가 너무 길어져서..보기가 좀 불편하지만..거의 모든 소스를 올려 놓은 것이니 다시 잘 만들어 보자. 소스 요청은 리플로 이메일을 남겨주면 된다.

Posted by MVP kaki104

댓글을 달아 주세요

2회에 이어 이제 본격적으로 시작을 해보자. 테이블 명세서는 1회에 있는 내용을 사용해서 만들 것이니 참고를 하면 돼고, 이번에는 Code First란 무엇인지 먼저 좀 알아보고, Code First를 이용해서 클래스를 만들고 데이터베이스를 만드는 과정을 하나 하나 보도록 하겠다.

1. 목표

1회에 보면 귀차니즘으로 인해 Model First로 작업을 하겠다고 했었는데..어쩔 수 없이 Code First로 작업을 해야한다. 이건 사연이 좀 있는데 엠에스에서 얼마전 EF(Entity Framework) 4.2를 정식 버전 배포를 했었는데.. 지금 사용하고 있는 EF버전은 4.1이다. 그러다 보니 Package형태로 배포가 된것인 듯하고, 또한 오직 Code First만을 지원한다....(이걸 알기 위해 몇시간 삽질을 했다는..)

음..아마도 다음에 EF4.5정도가 나오면 아마 두개가 합해져서 나오지 않을까 생각하며, 이 강좌(게시판 만들기)에서는 몇가지만 가지고 가면 될 것이다.

1-1. Code First 사용 방법

1-2. SQL Server Compact 4.0 - Streamlined Database의 개념 및 사용법

1-3. WCF RIA Service Support EF4.1 사용 방법

2. 강좌 관련 사이트 정리

ado.net team blog
http://blogs.msdn.com/b/adonet/

WCF RIA Services Support for EF 4.1 (and EF Code-First)
http://varunpuranik.wordpress.com/

RIA Services EF Code First Support
http://jeffhandley.com/

자세한 환경설정은 강좌 2번을 참고하고, 그렇게 해두 앙대면, 리플로 알려 주면 해결 방법을 찾아보겠다.

3. 만들기 시작
일단 BOARD_MAN이란 이름의 테이블 한개만 가지고 어떻게 만드는 것인지에 대한 내용을 정리하도록 하겠다.

3-1. 폴더 추가

SL5_BOARD.Web

DomainService, Model 2개의 폴더 추가

3-2. BOARD_MAIN 작업

먼저 Model폴더에 클래스 추가 -> 이름 : BOARD_MAIN.cs

//Key를 잡기 위해서 추가함
using System.ComponentModel.DataAnnotations; 

namespace SL5_BOARD.Web.Model
{
    public class BOARD_MAIN
    {
        [Key]
        public int BOARD_MAIN_IDX { get; set; }
        public string BOARD_NAME { get; set; }
        public string BOARD_TYPE { get; set; }
        public bool MEMBER_CHECK { get; set; }
        public string BOARD_DESC { get; set; }
        public string BOARD_STATE { get; set; }
        public DateTime REG_DT { get; set; }
        public int REG_IDX { get; set; }
        public DateTime? UPT_DT { get; set; }          //Null허용 DateTime은 반드시 필요, String은 그냥 둬두댐
        public int? UPT_IDX { get; set; }                  //Null허용
    }
}

음..정확하게 할려면 문자열의 길이도 정하고 해야겠지만 생략한다. 이렇게 하면 하나의 레코드를 정의 한 것이다. 음..어려운 것 없다는..ㅋㅋ

주의 할 점은 클래스에 반드시 하나이상의 Key필드가 존재 해야 한다는 것인데, 예를 들어 처음 필드명이 ID로 끝나는 단어를 가지고 있다면 그 필드는 자동을 Key로 인식이 되고, ID가 아니면 명시적으로 [Key]를 붙여 주어야 한다.

모든 필드에 값을 넣을 수 없을 때 Null허용 필드를 만들기 위해서는 타입뒤에 ?를 붙여서 Null허용을 표시한다. (DateTime필드는 꼭 붙여주어야 한다.)

3-3. Database 작업

using System.Web;
using System.Data.Entity;

namespace SL5_BOARD.Web.Model
{
    //맨뒤에 DbContext가 바로 이 클래스를 Db로 인식시키는 넘이다.
    public class SL5_BOARD_DBCONTEXT : DbContext
    {
        //생성자에서.. : base("SL5_BOARD") 라는 부분이 생략되면 로컬에 있는 sqlexpress DB를 사용하는 걸로 간주한다.
        //여기서는 Web.config에 있는 SL5_BOARD라는 ConnectionString을 사용하도록 지정되어 있다.
        public SL5_BOARD_DBCONTEXT()
            : base("SL5_BOARD")
        {
            //기존 Code First에 없던 내용으로 WCF RIA Service에서만 추가된 내용으로 디자인 타임에서
            //Database 생성을 하지 않도록 하기 위한 내용이다.
            if (HttpContext.Current == null)
            {
                //원래 여기도 맨뒤에 길게 꼬리가 붙어있는데 WCF RIA Service에서는 null로 처리를 한다.
                Database.SetInitializer<SL5_BOARD_DBCONTEXT>(null);
            }
        }
        //Table 객체
        public DbSet<BOARD_MAIN> BOARD_MAINS { get; set; }
    }
}


먼저 Model폴더에 클래스 추가 -> 이름 : SL5_BOARD_DBCONTEXT.cs음..그럼 일단 데이터베이스 만들고, 테이블 만드는 것 까지는 했다. 위해서 이야기를 했지만 Code First는 기본으로는 로컬 컴퓨터에 sqlexpress를 기본 DB로 생각하고 있지만.. 강좌에서는 Compact DB를 사용하기로 했기 때문에 Web.config를 설정해야한다. (이것도 30분정도 삽질해서 찾아낸 내용이라는..;; 뭐든지 쉬운것은 하나도 없다. )

3-4. Web.config

<connectionStrings>
  <add name="SL5_BOARD"
       providerName="System.Data.SqlServerCe.4.0"
       connectionString="Data Source=|DataDirectory|\SL5_BOARD.sdf"/>   
</connectionStrings>

딱 위의 문장이다..하지만, 그냥 아..그렇구나하고 넘어가면 에러 하나가 무지하게 괴롭힐 것이다. 왜일까? 우리는 DB를 웹서버 바로 아래 놓을 것이기 때문에 상대 경로를 적어 주어야 한다. 요기서 상대경로 지정 방법을 알고 있다면 패스하고 다음으로 넘어가도 좋다.

3-5. ASP.NET Folder추가
SL5_BOARD.Web -> 오른쪽 마우스 클릭 -> Add -> Add ASP.NET Folder -> App_Data
이렇게 지정한다. 그럼 SL5_BOARD.Web 프로젝트에 App_Data라는 폴더가 추가되고, 그 폴더를 지칭하는 문자열이 |DataDirectory| 이다 왼쪽 오른쪽에 |문자가 존재한다.

3-6. Database File 추가
않한다. 패스~ 그냥 폴더만 만들어 놓는다;;

3-7. Domain Service추가
DomainService 폴더에 SL5_BOARDDomainService.cs라는 클래스 추가

//추가
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.EntityFramework;
using SL5_BOARD.Web.Model;
using System.Data.Entity.Infrastructure;
using System.Data;

namespace SL5_BOARD.Web.DomainService
{
    //이번에 새로 나온 내용~
    [EnableClientAccess]
    //                                                        이넘두 새로 나온 내용
    public class SL5_BOARDDomainService : DbDomainService<SL5_BOARD_DBCONTEXT>
    {
        //기본 조회
        public IQueryable<BOARD_MAIN> GetBoardMain()
        {
            return this.DbContext.BOARD_MAINS;
        }
        //Insert 작업 처리부
        public void InsertBoardMain(BOARD_MAIN entity)
        {
            DbEntityEntry<BOARD_MAIN> entityEntry = this.DbContext.Entry(entity);
            if ((entityEntry.State != EntityState.Detached))
            {
                entityEntry.State = EntityState.Added;
            }
            else
            {
                this.DbContext.BOARD_MAINS.Add(entity);
            }
        }
        //Update 작업 처리부
        public void UpdateBoardMain(BOARD_MAIN entity)
        {
            this.DbContext.BOARD_MAINS.AttachAsModified(entity, this.ChangeSet.GetOriginal(entity), this.DbContext);
        }
        //Delete 작업 처리부
        public void DeleteBoardMain(BOARD_MAIN entity)
        {
            DbEntityEntry<BOARD_MAIN> entityEntry = this.DbContext.Entry(entity);
            if ((entityEntry.State != EntityState.Deleted))
            {
                entityEntry.State = EntityState.Deleted;
            }
            else
            {
                this.DbContext.BOARD_MAINS.Attach(entity);
                this.DbContext.BOARD_MAINS.Remove(entity);
            }
        }
    }
}

Select하는 부분은 WCF RIA Serivce 4.0과 흡사 하지만, Insert, Update, Delete부분은 큰 차이가 있는데, 그것은 4.0에서는 레코드를 Object로 처리를 하고, 5.0은 엔티티로 처리를 한다는 것이다. 에..그게 정확하게 무슨 의미냐구 반문을 해도 딱히 한 단어로 설명을 하기는 어렵고.. 디버그나 앞으로 작업을 하면서 어떤 것인지 직접 느껴야 할 것이다. 자세한 설명은 다음으로..일단 미룬다..

3-8. 빌드를 하고 실행해보자
빈화면이 이쁘게 잘뜨고 에러도 없으면 일단 성공이다. 에러가 Workspace를 불러 올수 없다는 그런 오류가 뜨면, 어딘가가 틀렸을 것이니 다시 차근 차근 검사를 하기 바란다. 그럼 이제 실버라이트로 넘어가 보자

3-9. SL5_BOARD 프로젝트 -> MainPage.xaml
화면 왼쪽 사이드 메뉴 중에 Data Sources라는 텝이 보일 것이다. (SL4 WCF RIA 프로그램 강좌 참고) 눌러 보면 SL5_BOARDDomainContext라는 내용이 보이면서 BOARD_MAIN이란 항목이 표시 된다.(처음에 뜰때 시간이 걸리니 약간 인내하자)
BOARD_MAIN을 드래그해서 MainPage.xaml 하면에 드롭하면 자동으로 코드가 생성된다. 그리고 실행해보자. 한번에 여기까지 성공을 하면 당신은 천재 일지도 모른다..(여기까지 작업하는데 3시간 정도 걸렸었다;;)

비록 보이는건(그리드 헤더는 보인다) 없지만, 오류없이 화면만 잘 떠도 성공적인 것이다. 그런데, 궁금하지 않나? 과연 데이터베이스는? 테이블은? 데이터는? 아까 우린 데이터베이스를 만든적도 없고, 그냥 연결문자열만 작성하고 넘어왔었다. 그런데 어떻게 화면에 내용이 나올까??

WCF RIA Service support EF4.1 Code First 에서는 SL5_BOARD_DBCONTEXT 넘이 인스턴스 될때 모든 작업을 백그라운드로 처리를 한다. 데이터 베이스를 만들고, 테이블을 만들고, 머 또 다른 할일있으면 하는.. 그럼 이제 아까 SL5_BOARD.Web 프로젝트에 만들어 놓은 App_Data폴더를 열어보자..(탐색기로 찾아가자) 아마 깜짝 놀랄지도..

VS2010 화면 왼쪽 사이드 메뉴 중에 Server Explorer 텝을 클릭 -> Data Connections에서 오른쪽 마우스 클릭 -> Add Connection 을 선택해서 새로 생긴 파일을 선택해서 내용을 확인해보자. 테이블도 이쁘게 만들어져 있을 것이다.


3-10. 추가 작업(CRUD)
SL5_BOARD 프로젝트 -> Add Reference -> System.Windows.Data 추가

3-11. MainPage.xaml 화면 개선 작업

화면에 버튼을 3개를 추가하고 더블 클릭해서 이벤트를 연결해 준다.

3-12. MainPage.xaml.cs

using SL5_BOARD.Web.Model;

//3개의 버튼의 클릭 이벤트를 모두 여기로
private void button1_Click(object sender, RoutedEventArgs e)
{
    Button btn = sender as Button;
    switch (btn.Content.ToString())
    {
        case "Insert":
            //DTO객체를 만들고
            BOARD_MAIN bm = new BOARD_MAIN();

            //날짜를 입력(날짜를 앙넣어주면 0001/01/01로 초기값이 들어가는데 오류남)
            bm.REG_DT = DateTime.Now;
            bm.REG_IDX = -1;

            //일단 새로 만든걸 추가하고
            bOARD_MAINDomainDataSource.DataView.Add(bm);

            //바로 서브밋 - 서브밋을 하자마자 ID가 부여되어서 바로 보임
            bOARD_MAINDomainDataSource.DomainContext.SubmitChanges();
            break;
        case "Update":
            //서브밋
            bOARD_MAINDomainDataSource.DomainContext.SubmitChanges();
            break;
        case "Delete":
            //선택된 아이템이 있을 경우
            if (bOARD_MAINDomainDataSource.DataView.CurrentItem != null)
            {
                //선택된 아이템 삭제
                bOARD_MAINDomainDataSource.DataView.Remove(bOARD_MAINDomainDataSource.DataView.CurrentItem);
                //서브밋
                bOARD_MAINDomainDataSource.DomainContext.SubmitChanges();
            }
            break;
    }
}


3-13. 일단 여기까지만 하도록 하자..화면을 실행해서 Insert버튼도 눌러보고, Update버튼도 눌러보고..

DB에 저장대고 삭제되는 과정들을 쭈욱 한번씩 보기 바란다. 그리고, 소스는 당분간 리플로 요청한 분들에 한해서만 보내 주는 방향으로 하겠다. 같이 해야 가치가 있다는.. 굿굿한 신념으로..함께 차근 차근 만들면서 진행해야 실력이 는다.

에러도 먼저 맞은 넘이 낳고, 일찍 에러나는 코딩이 오래간다!

그럼


 

 

Posted by MVP kaki104

댓글을 달아 주세요