2017-12-06 24 views
1

테이블에 엔티티를 삽입하는 메소드가 있습니다. 그러나 추가 할 엔티티가 존재하는지 확인하는 기능을 추가하고 싶습니다. Matcher 프롭퍼티 (Name 등)에 근거하는 테이블 이 코드를 실행하면 'SQL에 지원되는 변환이 없습니다'라는 메시지가 체크 라인에 나타납니다. 내 코드 부분은 아래와 같습니다. 이 문제를 어떻게 해결할 수 있습니까?Linq 일반 삽입 메소드를 사용할 때 SQL 예외가 SQL 예외로 변환되지 않습니다

public static InsertStatus Add<T>(T ent, string matcherProp) where T : class 
    { 
     System.Data.Linq.Table<T> t = otdc.GetTable<T>(); 

     //Exception on this line 
     if (t.Any(item => object.Equals(GetPropValue(item, matcherProp), GetPropValue(ent, matcherProp)))) 
      return InsertStatus.AlreadyExists; 

     try 
     { 
      t.InsertOnSubmit(ent); 
      otdc.SubmitChanges(); 
      return InsertStatus.Successfull; 
     } 
     catch 
     { 
      return InsertStatus.UnknownError; 
     } 
    } 
    public static object GetPropValue(object src, string propName) 
    { 
     return src.GetType().GetProperty(propName).GetValue(src, null); 
    } 
+0

GetPropValue를 SQL로 변환 할 수 없습니다. Linq-to-SQL 공급자가 이해할 수있는 'Expression'이 필요합니다. –

답변

2

런타임시 expresion 트리를 만들어야합니다. 다행히도 이것은 매우 어렵지 않습니다.

p => p.{matcherProp} == {val} 
matcherProp 테스트 할 멤버의 이름입니다

val이 같은 기존의 값입니다 이것이하는 일은 대한 논리적 트리를 구성이다

var p = Expression.Parameter(typeof(T), "p"); 
var val = GetPropValue(ent, matcherProp); 
var test = Expression.Lambda<Func<T, bool>>(
    Expression.Equal(
     Expression.PropertyOrField(p, matcherProp), 
     Expression.Constant(val) 
    ), p); 

if (t.Any(test)) 
    return InsertStatus.AlreadyExists; 

: 뭔가처럼이 될 것입니다 상수. 및 Expression.Constant에 공급 - 당신이 valnull 경우 당신은 또한합니다 (PropertyInfo.PropertyType) 속성의 유형를 제공 할 수 있습니다하지 않는 한, 문제를 얻을 수 있습니다

참고.


편집 :

p => p.{matcherProp} == ent.{matcherProp} 

는 람다에서 ent 훨씬 동작 여기서

var p = Expression.Parameter(typeof(T), "p"); 
var test = Expression.Lambda<Func<T, bool>>(
    Expression.Equal(
     Expression.PropertyOrField(p, matcherProp), 
     Expression.PropertyOrField(Expression.Constant(ent), matcherProp), 
    ), p); 

이가 다음 더 가깝다 :이 작업을 수행하는 또 다른 방법은 상수로 ent을 공급하는 것입니다 "캡처 된 변수"와 같습니다.

0

matcherProp을 문자열로 만드는 대신 Expression<Func<T, P>>으로 지정하여 Add(myEntity, e => e.Name)으로 호출 할 수 있습니다.

는 그런 다음 해당 오류는 물론 검사와

public static InsertStatus Add<T>(T ent, Expression<Func<T,P>> keySelector) where P : class 
{ 
    System.Data.Linq.Table<T> t = otdc.GetTable<T>(); 

    var memberAccess = (keySelector as LambdaExpression)?.Body as MemberExpression; 
    ParameterExpression paramExpr = Expression.Parameter(typeof(T), "e"); 
    Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T,bool>>(
      Expression.Equal(memberAccess.Update(Expression.Constant(ent)), memberAccess.Update(paramExpr)), paramExpr); 

    if (t.Any(predicate)) 
    { 

뭔가를해야합니다.