2009-11-18 3 views
3

우리는 빠른 조인을 위해 1 : 1 관계가 여러 개있는 클래스가 여러 개 있는데 표 형식 디스플레이의 경우 익명 형식에서는 잘 작동하지만 전체를 단일 linq 쿼리에서 유형을 채 웁니다.단일 쿼리에서 Linq-to-SQL로드 1 : 1 관계

우리는 1 : 1로 설정되어 있지 않기 때문에 이러한 속성을 갖거나 모든 디스플레이에 "기본"을 찾기 위해 하위 컬렉션을 쿼리하지 않으려 고합니다. 대신 저장시 이러한 기본 ID를 설정하여 비용이 발생합니다 .

A는이 글의 문맥 예를 벗었 콘택트들의 목록을 표시 할 때

public class Contact 
{ 
    public long Id { get; set; } 

    public EntitySet<Address> Addresses { get; set; } 
    public EntityRef<Address> PrimaryAddress { get; set; } 
    public long? PrimaryAddressId { get; set; } 

    public EntitySet<Email> Emails { get; set; } 
    public EntityRef<Email> PrimaryEmail { get; set; } 
    public long? PrimaryEmailId { get; set; } 

    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

public class Address 
{ 
    public long Id { get; set; } 
    public EntitySet<Contact> Contacts { get; set; } 

    public bool IsPrimary { get; set; } 
    public string Street1 { get; set; } 
    public string Street2 { get; set; } 
    public string City { get; set; } 
    public string State { get; set; } 
    public string Country { get; set; } 
} 

public class Email 
{ 
    public long Id { get; set; } 
    public EntitySet<Contact> Contacts { get; set; } 

    public bool IsPrimary { get; set; } 
    public string Address { get; set; } 
} 

문제는 상기와 PrimaryAddressPrimaryEmail로드 지연해야한다. 1 예 : : 그것은 부모의 관계처럼 취급하기 때문에 INNER에서

var DB = new DataContext(); 
var dlo = new DataLoadOptions(); 
dlo.LoadWith<Contact>(c => c.PrimaryAddress); 
dlo.LoadWith<Contact>(c => c.PrimaryEmail); 
DB.LoadOptions = dlo; 

var result = from c in DB.Contacts select c; 
result.ToList(); 

위의 코드 결과 가입하세요, 그것은 아무튼 우리가 DataLoadOptions을 할 경우는 1 이후 중 원하는 효과를 제공하지 않습니다 Nullable FK 관계를 존중하고 1 : 1 속성을 남겼습니다. 인구 1 속성, 심지어 목록 :

Select t1.*, t.2*, t3.* 
From Contact t1 
Left Join Address t2 On t1.PrimayAddressId = t2.Id 
Left Join Email On t1.PrimaryEmailId = t3.Id 

이 작업을 수행하고이 널 (NULL) (1)으로 된 IQueryable을 얻을 수있는 방법이 있나요 : 원하는 쿼리는 뭔가 같은 것? 다른 제약으로 인해 유형을 Contact으로 지정해야하므로 익명 유형이 작동하지 않습니다. 옵션에 매우 개방적이며, 우리가 표시하는 행 수에 대한 지연 쿼리 n * (1 : 1 수) +1 쿼리를 지연로드하는 것보다 낫습니다.

답변

2

업데이트 : 마지막으로이 문제를 해결하기 위해 devart는 완벽하게 작동하도록 이후 버전의 동작을 수정했습니다. DataLoadOptions 필요는 예를 들어, 테이블 작품 떨어져 필드를 사용하여 전혀 없습니다 :

var DB = new DataContext(); 
var result = from c in DB.Contacts 
      select new { 
       c.Id 
       c.FirstName, 
       c.LastName, 
       Address = c.PrimaryAddress.Street1 + " " + c.PrimaryAddress.Street2 //... 
       Email = c.PrimaryEmail.Address 
      }; 

이 올바르게 하나의 왼쪽 외부 관련 AddressEmail 테이블에 조인을 수행. 이제 픽스는이 익명 유형을 얻는 상황에 따라 다르지만 ... 을 수행하는 DataLoadOptions 동작을 수정했습니다. 이제에 올바르게 외래 키 유형을 입력해야합니다. 이 업데이트가 이전 버전의 다른 사용자에게 도움이 되었기를 바랍니다 ... 업그레이드를 권장합니다. 5.35 버전 이후 많은 새로운 기능 향상이 있습니다 (많은 사람들이 을 많이 만들었습니다.).


원본 : 우리가 결국 무엇
는 다른 접근 방식이었다. 이는 devart: dotConnect for Oracle 공급자 (버전 5.35.62에서이 동작이 변경된 경우이 질문을 시도하고 업데이트 함) 특정 동작 일 수 있습니다.

var DB = new DataContext(); 
var result = from c in DB.Contacts 
      select new { 
       c.Id 
       c.FirstName, 
       c.LastName, 
       Address = new AddressLite { 
           Street1 = c.PrimaryAddress.Street1, 
           Street2 = c.PrimaryAddress.Street2, 
           City = c.PrimaryAddress.City, 
           State = go.PrimaryAddress.State, 
           Country = go.PrimaryAddress.Country }, 
       Email = c.PrimaryEmail.Address 
      }; 
result.ToList(); 

이렇게하면 단일 쿼리가 생성됩니다. 선택 항목에서 하위 개체를 호출하는 동안 (예 : c.PrimaryAddress이 아닌 경우은 (표시되는 테이블 형식 데이터의 행당 하나씩) select ... from address where id = n 지연로드를 발생시킵니다. c.PrimaryAddress.Street1DOES은 쿼리 쿼리의 주소 테이블에 올바른 왼쪽 조인을 발생시킵니다. 위의 linq는 linq-to-sql에서만 작동하며, linq-to-entities에 대해서는 null 참조로 실패하지만 ... 우리가 처리하는 경우에는 괜찮습니다.


좋은 :

  • 단일 쿼리, 생산 왼쪽 (둘 다 몇 백을 이메일 단지 문자열로 주소와 아래 이메일로
  • 경량 객체 주소와 조인 실제 프로젝트의 EntiySet을 참조하면 테이블 형식의 디스플레이 요구에 비해 필요 이상으로 비싸게 만듭니다.)
  • 위의 내용은 우리가 직접 만든 모든 자식 테이블을 수동으로 결합하는 것보다 훨씬 간단합니다. oing, cleaner code.
  • 무거운 물체를 만들 때 전자 메일에서 문자열로, AddressLite에서 AddressLite로 (전체 프로젝트에서) Phone to PhoneLite로 변경하면 페이지 형식이 300 ~ 500ms에서 50 -100ms.

나쁜 :

  • 익명 타입 (ReSharper에서이 작업을 만들면서 심지어 빠른)들을 만들 필요 우리는 강한 형식이 필요합니다 경우이있다는 혼란을 많이 추가합니다.
  • 익명 형식을 수정하거나 저장할 수 없으므로 모델이 아무런 변화가없는 경우 업데이트해야합니다.(해당 클래스가 생성되지 않았기 때문에)
1

우리는 DataLoadOptions, 게으른로드 및 기본 레코드와 거의 동일한 문제에 대해 생각해 냈습니다.

정직하게 말하면 나는 솔직히 말해서 우리가 생각해 냈던 해결책이 완전히 만족스럽지 못했고, 생성되는 SQL 쿼리는 복잡 할 수 있지만 본질적으로 우리가 원하는 필드의 복사본으로 래퍼 클래스를 만들었습니다 강제로로드하고 하위 쿼리를 사용하여 레코드를로드합니다. 위의 예를 들면 다음과 같습니다

public class ContactWithPrimary 
{ 
    public Contact Contact { get; set; } 
    public Email PrimaryEmail { get; set; } 
    public Address PrimaryAddress { get; set; } 
} 

그런 다음 예제 LINQ 쿼리는 다음과 같습니다

List<ContactWithPrimary> Contacts = DataContext.Contacts 
    .Select(con => new ContactWithPrimary 
    { 
     Contact = con, 
     PrimaryEmail = con.PrimaryEmail, 
     PrimaryAddress = con.PrimaryAddress 
    }).ToList(); 

은 무엇 그러나 하는가하는 것은 하나의 쿼리에서 잡아 당깁니다입니다.

+0

아마도 우리 공급자 (오라클의 dotConnect)에 문제가있을 수 있습니다. 그러나 이것은 여전히 ​​왼쪽 조인 대신 하위 쿼리에서 조인 된 클래스 당 쿼리를 생성합니다 . 당신이 준 예제는 연락처 테이블에 대한 하나의 쿼리로 결과를 얻었고 각 1 : 1 테이블에 대한 결과 당 쿼리는 linq-to-sql에서 왼쪽으로 합쳐진 단일 쿼리를 얻었습니까? –

+0

우리는 SQLServer에 반대하고 있습니다. 위의 쿼리와 유사한 쿼리를 사용하면 코드를 직접 작성하는 것보다 훨씬 복잡하지만 단일 쿼리가 생성되었습니다. dotConnect에 대한 작업 경험이 없지만 표현 방식 트리를 다른 방식으로 처리하고 있으며 SQLServer 공급자와 마찬가지로 하위 쿼리를 생성하지 않는 것으로 보입니다. – RTPeat

0

Rob Conery의 Lazy List 구현을 살펴볼 수 있습니다.

http://blog.wekeroad.com/blog/lazy-loading-with-the-lazylist/

그것은 기본적에서 전체 게으른 로딩 구현을 숨기고 당신은 어떤로드 옵션을 지정할 필요가 없습니다.

유일한 단점은 목록에서만 작동한다는 것입니다. 그러나 속성에 대한 구현도 작성할 수 있습니다. 여기 내 노력이있다.

public class LazyProperty<TEntityType> where TEntityType : class 
{ 
    private readonly IQueryable<TEntityType> source; 
    private bool loaded; 
    private TEntityType entity; 

    public LazyProperty() 
    { 
     loaded = true; 
    } 

    public LazyProperty(IQueryable<TEntityType> source) 
    { 
     this.source = source; 
    } 

    public TEntityType Entity 
    { 
     get 
     { 
      if (!loaded) 
      { 
       entity = source.SingleOrDefault(); 
       loaded = true; 
      } 
      return entity; 
     } 
     set 
     { 
      entity = value; 
      loaded = true; 
     } 
    } 
} 
1

EntityRef 유형의 특성에 대한 연관 속성에서 IsForeignKey가 false로 설정되면 왼쪽 조인이 생성됩니다.