2010-01-16 1 views
1

두 테이블 간의 외래 키 관계가있는 Linq to SQL EntitySet이 있습니다. 해당 테이블은 작업 테이블 (Issues라고 함)과 부서 테이블입니다. 외래 키는 부서명 (어느 것이 고유한지)입니다. 관련 데이터가로드 된 경우 Linq to SQL FK 필드를 변경할 수 없다는 문제가 있습니다.wpf 콤보 상자를 Linq to SQL 외래 키 속성에 바인딩하는 방법

뷰 모델은 (진실하지 MVVM, 내가 XAML, WPF 및 Linq는-SQL을 배우면서 개념을 실천하기 위해 노력하고 있어요)

public class StatusBoardViewModel : INotifyPropertyChanged 
{ 
    OIConsoleDataContext db = new OIConsoleDataContext(); 

    private IQueryable<Issue> issues; 
    public IQueryable<Issue> Issues 
    { 
     get { // Lazy load issues if they have not been instantiated yet 
      if (issues == null) { 
       QueryIssues(); 
      } 
      return issues; 
     } 
     set { 
      if (issues != value) { 
       issues = value; 
       OnPropertyChanged("Issues"); 
      } 
     } 
    } 

    private IQueryable<Department> departments; 
    public IQueryable<Department> Departments 
    { 
     get { 
      // Lazy load departments if they have not been instantiated yet 
      if (departments == null) { 
       QueryDepartments(); 
      } 
      return departments; 
     } 
     set { 
      if (departments != value) { 
       departments = value; 
       OnPropertyChanged("Departments"); 
      } 
     } 
    } 

    private void QueryDepartments() 
    { 
     Departments = from d in db.Departments 
         orderby d.DeptName 
         select d; 
    } 

    public void QueryIssues() 
    { 
     Issues = from i in db.Issues 
       where i.IssIsOpen == true 
       orderby i.IssDueDate 
       select i; 
     // .... 
    } 

    #region INotifyPropertyChanged Members 
} 

내 콤보 상자 :

<ComboBox x:Name="DeptComboBox" 
    ItemsSource="{Binding Departments}" 
    DisplayMemberPath="DeptName" 
    SelectedValuePath="DeptName" 
    SelectedValue="{Binding Path=Issues/IssDepartment, Mode=TwoWay}" 
    Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="3" Margin="6,7,115,5" 
    IsSynchronizedWithCurrentItem="True" /> 

는 그것을 의미로 콤보 상자를 잘 표시하고 선택 항목을 올바른 부서로 기본 설정하지만 변경하면 예외가 발생합니다. 'System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException'

다음 다음 새 하나를 추가 부서 참조를 제거 뒤에 다음 코드를 사용하여 콤보 상자에

SelectionChanged="DeptComboBox_SelectionChanged" 

를 추가했습니다. 잘 작동하는 것처럼 보였지만 필터 설정에 따라 linq 쿼리가 변경된 경우 Selection_Changed 이벤트가 발생하면 변경 전의 새 항목이 새 기본 항목 부서의 값으로 변경됩니다. 선택 변경 이벤트가 바인딩 속성이 아니라이를 방지하기 위해 사용자가 보낸 것인지 확인할 수있는 방법을 찾지 못했습니다. 게다가 코드 바인딩을 사용하거나 적어도 어떤 종류의 값 변환기에 있어야하는 코드 사용에 만족하지 않았습니다.

나 자신에게 정직해야
// This was an attempt to work around that did not work 
// The referneces are passed from the Window1 event handler 
public void ChangeDepartment(Issue currentIssue, Department currentDept) 
{ 
    if (currentIssue != null) { 
     currentIssue.Department = null; 
     currentIssue.Department = currentDept; 
    } 
} 

,

나는이 어떻게

처리해야 .. 여기 내 급여 등급 이상에서 오전 있지만 가장 어 배울 때이다? 나는 그 문제에 관한 12 개의 기사를 읽고 그것들이 진흙처럼 모순되고 분명한 것으로 판명했다. 모든 도움을

감사 SO

나는 아래 크리스 니콜과 매우 유용한 토론이 있고 나는 일에 더 나은 핸들이 있다면 그는 이미 확인 표시가 아마 것 마이크

업데이트 . 필자는 가장 큰 문제는 SQL, Linq, WPF 및 데이터베이스 디자인을 한꺼번에 배우는 것입니다. 나는 모든 주제에 대해 훌륭한 책을 가지고 있지만 상호 운용성에 대해서는 다루지 않습니다. 예를 들어 C# 2008의 Pro Linq는 훌륭합니다 ... WPQ의 Linq에 대해 전혀 이야기하지 않는 것을 제외하고는

가능한 한 "MVVMish"로 작업하려고했지만 이전에 몇 차례 잘못 시작한 후, 한 번에 배울 수있는 것이 너무 많다는 결론을 내 렸습니다. 실제로는 명령이 없다는 것을 제외하고는 MVVM에 가깝다고 생각합니다. 코드 뒤의 이벤트 핸들러에서 ViewModel 클래스의 메서드를 실행합니다. 나중에 지휘 체계에서 리팩토링하는 것이 상당히 쉽다고 가정하고 있습니다.

모델

  • Linq에이 파일 DBML SQL로 DataErrorInfo 확인을위한
  • 부분 클래스를

뷰 모델

  • 를 다음과 같이 내 응용 프로그램이 구성되어 DataCon 다른 목록 상자를 트리거 텍스트
  • (ShowDetailListItems 같은 바인딩 할 보려면 추가/편집 창보기로
  • 일부 속성을 사용하는 작업, 직원 및 부서
  • 선택된 작업의 속성에 대한
  • 된 IQueryable 컬렉션) ItemTemplate 자체이며 확인란 자체에 바인딩됩니다.
  • querys를 수행하는 메소드
  • 태스크를 추가하거나 편집하기위한 창을 열고 해당 창에서 복귀 할 때 submitChanges() 메소드.

보기는 뷰 모델에 바인딩하고 코드 뒤에이 포함되어 있습니다 :

  • 생성자의 뷰 모델의 인스턴스를 뷰 모델 클래스
  • 코드의 인스턴스를 보유 속성과 viewModel에 datacontext를 설정하는 방법
  • 나머지 코드는 결과적으로 명령으로 대체되는 이벤트 처리기입니다.

나는 Josh Smiths 우수 기사를 여러 번 읽었으며 샘플 코드를 살펴 보았습니다. 내 형식의 대부분은 그것을 기반으로합니다. Chris (Below)가 목록을 작성한 스레드는 내가 탐구 할 톤이나 새로운 자료를 가지고 있으므로, 시간을 들여 파고 들어서 리팩터링하는 방법을 결정하려고합니다. 실제로 작동하지 않는 ComboBoxes를 훨씬 뛰어 넘었습니다. 실제로 원래 문제의 일부는 콤보 상자가 두 개의 다른 데이터 컨텍스트에 바인딩된다는 것입니다. 내가 관리할만한 아키텍처를 가질 때까지 나는 그 일을 패치하기 위해 노력하는 것이 더 해롭다 고 생각합니다.

아마

유감스럽게도 크리스

에 대한 확인 표시와 함께 나중에 다시 될 것입니다 : "시도가 부착하거나, 새로운 아마도 다른 DataContext에로드 된없는 엔티티를 추가하기위한 것으로 ..."

+0

좋아요. 나는이 작업을했지만 해결 방법은 내가 싫어하는 엄청난 해킹입니다.내 게시물의 끝에서 이벤트를 사용하여 'UpdatingQuery'클래스에 속성을 추가 한 다음 쿼리를 변경하는 동안이 속성을 true로 설정했습니다. 그런 다음 ChangeDepartment에 검사를 추가하여 업데이트가 지연되는 변경 사항을 제외했습니다. OUCH 옳은 길을 찾아야합니다. 나쁜 습관을 배우는 것이 싫어요! –

답변

2

데이터 액세스 레이어를 ViewModel에서 분리하고 관찰 가능한 컬렉션을 사용하는 것이 좋습니다. 일단 MVVM을 활용하면 이런 종류의 일이 그렇게 어렵지 않습니다.

나는 Josh Smith's article on MVVM을 읽는 것이 좋습니다. WPF에 대한 좋은 통찰력과 바인딩 기능을 제공합니다. 어떻게 작동하는지 이해하면 WPF에서 수행하려는 작업을 매우 쉽게 수행 할 수 있습니다.

행운을 빈다.

+0

만약 내가 이해한다면 Linq와 ObservableCollection 을 관리하기 위해 Ixtoolable 을 모두 유지해야 할 필요가 있습니다. 데이터베이스에 변경 사항이있을 때마다 IQueryable에 도달 한 후 ObservableCollection을 IQueryable의 새 복사본으로 덮어 씁니 까? –

+0

예 ... 또는 더 멀리 나눌 수 있고 ObservableCollection과 IQueryable 사이에 레이어가 있습니다.이 레이어는 지속되기 전에 작업 단위를 수집하는 계층입니다. –

+0

이것에 대해 약간의 독서를 제안 할 수 있습니까? 지금까지 리팩토링을 시도한 결과 "다른 DataContext에서로드 된 새로운 것이 아닌 엔티티를 첨부하거나 추가하려고 시도했습니다."예외가 발생했습니다. 데이터를 쿼리해야합니까? 그런 다음 바인딩을위한 ObservableCollection을 설정합니다. 변경된 경우 새 DataContext를 만들고 데이터를 쿼리 한 다음 해당 데이터 집합에 변경 내용을 적용하고 SubmitChanges()를 수행합니까? 그것은 지금도 db.GetChangeSet()에 대한 호출도 예외를 던지고있다. (GetChangeSet()이 아무 것도 변경하지 않기 때문에 이상하게 보임) –