C # LINQ to SQL :이 일반 GetByID 메서드 리펙토링

c# expression-trees generics linq-to-sql

문제

나는 다음과 같은 방법을 썼다.

public T GetByID(int id)
{
    var dbcontext = DB;
    var table = dbcontext.GetTable<T>();
    return table.ToList().SingleOrDefault(e => Convert.ToInt16(e.GetType().GetProperties().First().GetValue(e, null)) == id);
}

기본적으로 T 가 DataContext의 클래스 인 일반 클래스의 메소드입니다.

메서드는 T ( GetTable ) 유형에서 테이블을 가져 와서 입력 된 매개 변수에 대한 첫 번째 속성 (항상 ID 임)을 확인합니다.

이 문제는 내가 속성의 GetType 을 실행하기 위해 먼저 목록으로 요소 표를 변환해야했지만, 표의 모든 요소를 ​​열거하고 List 변환해야하기 때문에 매우 편리하지 않습니다.

전체 테이블에서 ToList 를 피하기 위해 어떻게이 메소드를 리팩토링 할 수 있습니까?

[최신 정보]

테이블에서 Where 직접 실행할 수없는 이유는이 예외가 발생했기 때문입니다.

메서드 'System.Reflection.PropertyInfo [] GetProperties ()'에는 SQL에 대한 지원되는 변환이 없습니다.

왜냐하면 GetProperties 는 SQL로 변환 될 수 없기 때문입니다.

[최신 정보]

어떤 사람들은 T 를위한 인터페이스를 사용하도록 제안했지만 문제는 T 매개 변수가 [DataContextName] .designer.cs 에서 자동 생성되는 클래스가 될 것이므로 인터페이스를 구현할 수 없다는 것입니다 (구현할 수 없습니다). LINQ의 모든 "데이터베이스 클래스"에 대한 인터페이스 및 DataContext에 새 테이블을 추가하면 파일이 다시 생성되어 모든 작성된 데이터가 손실됩니다.

그래서, 이것을하는 더 좋은 방법이 있어야합니다 ...

[최신 정보]

Neil Williams 의 제안과 같은 코드를 구현했지만 아직 문제가 있습니다. 다음은 코드의 발췌 부분입니다.

인터페이스 :

public T GetByID(int id)
{
    var dbcontext = DB;
    var table = dbcontext.GetTable<T>();
    return table.ToList().SingleOrDefault(e => Convert.ToInt16(e.GetType().GetProperties().First().GetValue(e, null)) == id);
}

DataContext [코드보기] :

public T GetByID(int id)
{
    var dbcontext = DB;
    var table = dbcontext.GetTable<T>();
    return table.ToList().SingleOrDefault(e => Convert.ToInt16(e.GetType().GetProperties().First().GetValue(e, null)) == id);
}

일반 방법 :

public T GetByID(int id)
{
    var dbcontext = DB;
    var table = dbcontext.GetTable<T>();
    return table.ToList().SingleOrDefault(e => Convert.ToInt16(e.GetType().GetProperties().First().GetValue(e, null)) == id);
}

이 줄에서 예외가 발생합니다. return table.SingleOrDefault(e => e.ID.Equals(id)); 예외는 다음과 같습니다.

System.NotSupportedException: The member 'MusicRepo_DataContext.IHasID.ID' has no supported translation to SQL.

[업데이트] 해결책 :

데니스 트롤러 (Denis Troller )의 게시판 답변과 코드 란 트 (Code Rant) 블로그 의 게시물 링크 덕분에 마침내 해결책을 찾을 수있었습니다.

public T GetByID(int id)
{
    var dbcontext = DB;
    var table = dbcontext.GetTable<T>();
    return table.ToList().SingleOrDefault(e => Convert.ToInt16(e.GetType().GetProperties().First().GetValue(e, null)) == id);
}

수락 된 답변

필요한 것은 LINQ to SQL에서 이해할 수있는 표현식 트리를 작성하는 것입니다. "id"속성의 이름은 항상 "id"라고 가정합니다.

public virtual T GetById<T>(short id)
{
    var itemParameter = Expression.Parameter(typeof(T), "item");
    var whereExpression = Expression.Lambda<Func<T, bool>>
        (
        Expression.Equal(
            Expression.Property(
                itemParameter,
                "id"
                ),
            Expression.Constant(id)
            ),
        new[] { itemParameter }
        );
    var table = DB.GetTable<T>();
    return table.Where(whereExpression).Single();
}

이것은 트릭을해야합니다. 이 블로그 에서 뻔뻔하게 차용했습니다. 이것은 기본적으로 LINQ to SQL이 다음과 같은 쿼리를 작성할 때 수행하는 작업입니다.

public virtual T GetById<T>(short id)
{
    var itemParameter = Expression.Parameter(typeof(T), "item");
    var whereExpression = Expression.Lambda<Func<T, bool>>
        (
        Expression.Equal(
            Expression.Property(
                itemParameter,
                "id"
                ),
            Expression.Constant(id)
            ),
        new[] { itemParameter }
        );
    var table = DB.GetTable<T>();
    return table.Where(whereExpression).Single();
}

T는 "id"속성을 가지고 있고 인터페이스의 임의 "id"속성을 데이터베이스에 매핑 할 수 없기 때문에 컴파일러가 생성 할 수 없으므로 LTS에 대한 작업 만 수행하면됩니다.

==== 업데이트 ====

좋아, 기본 키 이름을 찾는 단순한 구현은 하나만 있다고 가정하고 (복합 기본 키가 아님) 모든 유형이 적절하다고 가정합니다. 즉, 기본 키가 "짧은"유형과 호환됩니다. GetById 함수에서 사용) :

public virtual T GetById<T>(short id)
{
    var itemParameter = Expression.Parameter(typeof(T), "item");
    var whereExpression = Expression.Lambda<Func<T, bool>>
        (
        Expression.Equal(
            Expression.Property(
                itemParameter,
                "id"
                ),
            Expression.Constant(id)
            ),
        new[] { itemParameter }
        );
    var table = DB.GetTable<T>();
    return table.Where(whereExpression).Single();
}

인기 답변

어떤 생각 ...

ToList () 호출을 제거하면 SingleOrDefault는 테이블이 있다고 가정하는 IEnumerably와 함께 작동합니다.

e.GetType (). GetProperties (). First ()를 호출하여 PropertyInfo를 반환합니다.

그냥 T에 제약 조건을 추가하면 Id 속성을 노출하는 인터페이스를 구현하게 될까?




아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.