[MySQL EF 6] System.NotSupportedException: Unable to create a constant value of type [타입명] 예외 해결 방법

  해당 예외가 발생하는 이유는 여러가지가 있겠으나 이번에 제가 경험한 내용을 바탕으로 글을 쓰도록 하겠습니다. 이 방법으로 해결이 안 되는 분께선 구글신의 힘을 빌리도록 하시길 바랍니다.

잘못된 비교 로직

  여기 3개의 기본 키를 포함한 원시 타입과 1개의 외래 키 객체를 지니는 모델이 있습니다.
public class ExampleModel
{
    [Key]
    public int Id { get; set; }

    public decimal UpperLimitPrice { get; set; }

    public decimal MaximumPrice { get; set; }

    public UserModel User { get; set; }
}
  그리고 우리는 수많은 Example 중에서 특정 User와 일치하는 레코드를 가져오고자 합니다. 직관적인 예를 들면, 게시판이 있는 웹 서비스에서 '내 글 보기'와 같은 기능을 구현한다고 생각하시면 편합니다.

  이때, 아래와 같이 코딩을 하면 이 포스트의 제목과 같은 예외가 발생하게 됩니다.
_context.ExampleList.Where(ex => ex.User == userClient);
  왜일까요? 이유는 바로 EF에서 원시 타입이 아닌 객체의 비교를 지원하지 않기 때문입니다. 즉, string, int, long, float, double, decimal, ... 이런 타입이라면 비교가 가능하지만, 사용자가 직접 만든 클래스의 객체, 여기선 UserModel의 객체에 대한 비교는 지원하지 않는다는 것이죠.
  이유를 생각해보면 간단합니다. 우리가 SQL로 SELECT 쿼리를 날릴 때, 예를 들어 게시판에서 특정 유저가 쓴 글의 레코드만 가져온다고 하면
SELECT id, title, body, registeredDate FROM board WHERE userId = '[외래 키로 연결된 유저 테이블의 ID]'
이런 식으로 가져오죠? 우리가 EF의 Linq 기능을 사용해 코딩한 모든 내용은 이와 같은 SQL문으로 변환돼 DB 서버로 요청하게 됩니다. 하지만 WHERE문에 UserModel 객체를 통채로 집어넣어버리면 SQL문의 WHERE절에 들어갈 적절한 값을 어떻게 찾아야 할까요?
  물론, 기본적으로 PrimaryKey로 설정된 컬럼만 비교하게 하면 된다! 라고 생각할 수도 있지만, 조금만 생각해도 여러 문제가 발생할 여지가 있다는 걸 알 수 있습니다. 때문에 아예 원천적으로 원시 타입이 아닌 인자는 비교할 수 없게 해놓은 것입니다.

해결 방법? SQL 구문을 생각하면 간단

  그럼 해결 방법은 뭘까요? 사실, SQL 쿼리를 날리는 방법을 생각하면 아주 간단합니다. 위에도 예시로 써놨지만 SQL 쿼리를 날릴 때에는 WHERE userId = 1 과 같이 타겟 테이블의 특정한 컬럼 값으로 비교를 하죠? EF로도 똑같이 하시면 됩니다. 아래처럼요.
_context.ExampleList.Where(ex => ex.User.Id == userClient.Id);
  차이점이 보이시나요? UserModel 객체를 그대로 비교하지 않고 int UserModel.Id 값으로 비교를 했습니다. userClient의 Id가 1이라고 가정하고 SQL로 변환한다면 SELECT * FROM example_list WHERE user_id = 1이 되겠네요. 이제 더이상 위와 같은 예외는 보이지 않게 될 겁니다.

  참 쉽죠? 몇 글자 바꾸지도 않고 예외를 해결할 수 있다니. 이상으로 해당 예외의 해결 방법 중 하나에 대한 설명을 마칩니다. 모두 편안한 하루 되시기 바랍니다.

댓글

이 블로그의 인기 게시물

C# 남아도는 메모리에도 불구하고 OutOfMemoryException이 발생한다면?

USB를 뒤는 괜찮은데 앞에 꽂으면 인식이 힘들다?

MySQL 데이터 타입과 Java 데이터 타입 비교/매칭