2014-09-30 8 views
3

익명 형식을 생성하는 동적 선택기식이 있습니다. 이 객체에 LINQ에서 잘 작동,하지만 엔티티에 LINQ에, 그것은 예외 :동적 선택기 Linq To Entities

시도

만 매개 변수가없는 생성자와 초기화가 엔티티에 LINQ에서 지원되는 1

NotSupportedException이.

Expression<Func<User, T>> DynamicSelect<T>(T obj, ParameterExpression userParam) 
{ 
    var newExpression = Expression.New(
     typeof(T).GetConstructor(typeof(T).GenericTypeArguments), 
     userParam, 
     Expression.Constant("X"), 
     Expression.Constant("Y") 
    ); 
    return Expression.Lambda<Func<User, T>>(newExpression, userParam); 
} 

var userParam = Expression.Parameter(typeof(User), "u"); 
var obj = new { User = new User(), Address = string.Empty, Fax = string.Empty }; 
var arr = context.Set<T>() 
    .Select(DynamicSelect(obj, userParam)) 
    .ToArray(); 

시도 2 ​​, 나는 사용자 정의 유형을 작성하는 경우, 그것은 일하고,하지만 각 개체에 대한 추가 사용자 지정 형식을 만들지 않고이 도우미 방법을 다시 사용하려는 때문에 내가 싶지 않아, I 소비자를 기반으로 유형을 전달할 수 있기를 원합니다.

public class Container 
{ 
    public User User { get; set; } 
    public string Address { get; set; } 
    public string Fax { get; set; } 
} 
Expression<Func<User, T>> DynamicSelect<T>(T obj, ParameterExpression userParam) 
{ 
    var initExpression = Expression.MemberInit(
     Expression.New(typeof(T)), 
     Expression.Bind(typeof(T).GetProperty("User"), userParam), 
     Expression.Bind(typeof(T).GetProperty("Address"), Expression.Constant("X")), 
     Expression.Bind(typeof(T).GetProperty("Fax"), Expression.Constant("Y")) 
    ); 
    return Expression.Lambda<Func<User, T>>(initExpression, userParam); 
} 

var userParam = Expression.Parameter(typeof(User), "u"); 
var arr = context.Set<T>() 
    .Select(DynamicSelect<Container>(null, userParam)) 
    .ToArray(); 

시도 3

, 나는 또한 Tuple<User, string, string>를 사용하여 시도,하지만 너무 지원 아니에요.

NotSupportedException이

방법 'System.Tuple`3를 인식하지 못하는 엔티티에 LINQ [사용자, 선택 System.String, 선택 System.String] 만들기 [사용자, 문자열, 문자열 (사용자, 시스템 .String, System.String) ' 메서드이며이 메서드는 저장소 식으로 변환 할 수 없습니다.

Expression<Func<User, T>> DynamicSelect<T>(T obj, ParameterExpression userParam) 
{ 
    var createExpression = Expression.Call(
     typeof(Tuple), 
     "Create", 
     typeof(T).GenericTypeArguments, 
     userParam, 
     Expression.Constant("X"), 
     Expression.Constant("Y")); 
    return Expression.Lambda<Func<User, T>>(createExpression, userParam); 
} 

var userParam = Expression.Parameter(typeof(User), "u"); 
var arr = context.Set<User>() 
    .Select(DynamicSelect<Tuple<User, string, string>>(null, userParam)) 
    .ToArray(); 

이 도와주세요.

나는 각각의 소비자에게 특정 구현을하지 않고 어떤 소비자 (사용자, 고객, 동료 등)이 도우미 메서드를 다시 사용하려고했다

업데이트합니다.

클래스 구조는 다음과 같습니다.

public class User 
{ 
    public int Id { get; set; } 
    public string UserName { get; set; } 
    public virtual ICollection<Contact> Contacts { get; set; } 
} 
public class Customer 
{ 
    public int Id { get; set; } 
    public string CompanyName { get; set; } 
    public virtual ICollection<Contact> Contacts { get; set; } 
} 
public class Contact 
{ 
    public int Id { get; set; } 
    public string Type { get; set; } 
    public string Content { get; set; } 
} 
public class UserDto 
{ 
    public int Id { get; set; } 
    public string UserName { get; set; } 
    public ContactDto Contact { get; set; } 
} 
public class CustomerDto 
{ 
    public int Id { get; set; } 
    public string CompanyName { get; set; } 
    public ContactDto Contact { get; set; } 
} 
public class ContactDto 
{ 
    public string Email { get; set; } 
    public string Address { get; set; } 
    public string Fax { get; set; } 
    // other contact informations 
} 

그리고 나는 각 소비자마다 다를 수있는 많은 연락처가 있습니다. , Invoke 방법은 표현 LINQ에서 지원되지 않기 때문에 그것은 오류가 발생합니다

var users = context.Set<User>() 
    .Select(x => new UserDto 
    { 
     Id = x.Id, 
     UserName = x.UserName, 
     Contact = new ContactDto 
     { 
      Email = GetContactExpression("Email").Compile()(x) 
     } 
    }) 
    .ToArray(); 

:

var users = context.Set<User>() 
    .Select(x => new UserDto 
    { 
     Id = x.Id, 
     UserName = x.UserName, 
     Contact = new ContactDto 
     { 
      Email = x.Contacts.Where(c => c.Type == "Email").Select(c => c.Value).FirstOrDefault() 
     } 
    }) 
    .ToArray(); 

var customers = context.Set<Customer>() 
    .Select(x => new CustomerDto 
    { 
     Id = x.Id, 
     CompanyName = x.CompanyName, 
     Contact = new ContactDto 
     { 
      Address = x.Contacts.Where(c => c.Type == "Address").Select(c => c.Value).FirstOrDefault(), 
      Fax = x.Contacts.Where(c => c.Type == "Fax").Select(c => c.Value).FirstOrDefault(), 
     } 
    }) 
    .ToArray(); 

그리고 표현에 리팩토링,하지만 내가 좋아하는 방법 내에서 직접 사용할 수 없습니다 그래서 내가 전체 Select 표현을 리팩토링해야하지만 일반 (UserUserName을 가지고 있지만 CompanyName을 가진 Customer 및 기타 정보가 있어야 함)이 문제가 해결 된 후에도 접촉 유형을 전달할 필요가 있습니다.

var obj = new { User = new User(), Email = "" }; 
var users = context.Set<User>() 
    .Select(x => DynamicSelect(obj)) 
    .Select(x => new UserDto 
    { 
     Id = x.User.Id, 
     UserName = x.User.UserName, 
     Contact = new ContactDto 
     { 
      Email = x.Email 
     } 
    }) 
    .ToArray(); 
+0

표현식 생성기의 예상 동작이 다른 익명 형식에 어떤 영향을 미치는지 정의해야한다고 생각합니다. "Address"속성을 항상 기대할 수 있습니다. 예를 들어 "X"로 설정할 수 있습니까? – StriplingWarrior

+0

@StriplingWarrior, 일부 엔티티는'Contact' 테이블과 일대 다 관계를 가지고 있습니다. 상수 "X"는'user.Contacts.Where (c => c.Type ==)를 대체하기 위해 만든 다른 selector 표현식으로 대체 될 것입니다. "Address") Select (x => x.Text) .FirstOrDefault()', 상수를 사용하여 문제를 단순화 했으므로 예상 결과에는 항상 Address, Phone, Email과 같은 속성이 포함됩니다. 이 도우미가 주체 유형 (사용자, 고객 등)의 매개 변수와 추출 할 연락처의 유형을 받아 들일 수 있기를 바랍니다. 하지만 지금은'u => new {User = u}'를 표현식으로 대체해야합니다. – tsuta

+0

먼저 구체화하십시오. 이후에 동적 선택을 사용 하시겠습니까? (동적 선택 <...> (...)) ' – B0Andrew

답변

4

내가 u => new { User = u, Address = "X", Fax = "Y" } 같은 뭔가를 컴파일러에 의해 생성 된 하나 표현식을 비교하면 차이는 후자가 Members을 채운 것입니다 : 순간에 예상되는 결과는 무엇인가 lile 될 것이다.

Members이 전혀 존재하지 않는 이유는 무엇인지 모르겠지만 설정하려고합니다. 내 생각에 문제가 해결 될 것입니다. 코드는 다음과 같을 수 있습니다.