2014-07-07 3 views
0

저는 EF를 통해 데이터베이스 액세스를 간소화하기 위해 LINQ 확장을 구축 중이며 해당 프로세스의 일부는 데이터 엔터티를 비즈니스 엔터티에 매핑하는 것입니다.정적 클래스에서 요청 별 변수를 사용하는 더 좋은 방법이 있습니까?

나는 포함 할 탐색 속성과 깊이를 결정하기 위해 Dictionary<string, int>을 사용합니다.

예 :이 내 저장소에 나에게 접근 물건을 할 수 있습니다 및 서비스

public static class LinqExtensions 
{ 
    private static readonly Dictionary<string, int> Dictionary = new Dictionary<string, int>(); 

    /// <summary> 
    /// Adds the navigational property identified by value to be included in the query and entity mapping, recursing a maximum of depth times. 
    /// </summary> 
    /// <param name="value">Navigational Property to add</param> 
    /// <param name="depth">Desired recursion depth</param> 
    public static TSource With<TSource>(this TSource source, string value, int depth = 0) 
    { 
     Dictionary.Add(value, depth); 
     return source; 
    } 

    /// <summary> 
    /// Clears the navigational property dictionary 
    /// </summary> 
    public static void Reset() 
    { 
     Dictionary.Clear(); 
    } 

    /// <summary> 
    /// Builds and executes a query, dynamically including desired navigational properties in a asynchronous fashion. 
    /// The result is then mapped to the provided TResult business entity and returned as a list. 
    /// </summary> 
    /// <returns>Null or a list of mapped domain Entities</returns> 
    public static async Task<IEnumerable<TResult>> BuildQueryAsync<TSource, TResult>(this IQueryable<TSource> dbEntity) where TResult : class, new() 
    { 
     var query = dbEntity; 
     var localDictionary = new Dictionary<string, int>(Dictionary); 
     Reset(); 

     foreach (var i in localDictionary) 
     { 
      query = query.Include(i.Key); 
     } 
     List<TSource> result = await (from entity in query select entity).ToListAsync(); 

     return Equals(result, default(TSource)) ? null : result.Select(u => u.BuildEntity(new TResult(), localDictionary)); 
    } 

    /// <summary> 
    /// Maps values from sourceEntity to targetEntity, recursing into properties defined in localDictionary. 
    /// </summary> 
    public static TTarget BuildEntity<TSource, TTarget>(this TSource sourceEntity, TTarget targetEntity, Dictionary<string, int> localDictionary) 
    { 
     return (TTarget)targetEntity.InjectFrom(new SinglePropertyDepthInjection(localDictionary), sourceEntity); 
    } 
} 

다음과 같이

public override async Task<IEnumerable<User>> GetAllAsync() 
    { 
     return await _context.Users.With("Messages", 1).With("Notifications", 2).BuildQueryAsync<Data.Entities.User, User>(); 
    } 

지금 내가 인해 정적 속성이이 가능하지 않을 것을 잘 알고 있어요 모든 요청에서 공유됩니다.

나는 easilly 메소드 매개 변수로 사전을 추가 할 수 있습니다 알고, 같은 그것을 해결 :

public override async Task<IEnumerable<User>> GetAllAsync() 
    { 
     var dict = new Dictionary<string, int>(); 

     dict.Add("Messages", 1); 
     dict.Add("Notifications", 2); 

     return await _context.Users.BuildQueryAsync<Data.Entities.User, User>(dict); 
    } 

그러나 아마 더 우아한 해결책이 있다면 나는의 일부로 유지 이상적으로, 궁금 해서요 LINQ 쿼리.

내가 알고있는 것은 HttpContext.Current이지만 관련 메소드가 비동기 적이기 때문에 컨텍스트 스레드로 돌아가는 것이 얼마나 좋은 아이디어인지 잘 모르겠습니다.

아이디어가 있으십니까?

답변

1

나는 CallContext가 당신이 찾고있는 것 같아요.

일회용 패턴과 함께 이러한 일들은 매우 쉽게 적용 할 수 있습니다.

public class IncludeScope : IDisposable 
{ 
    private const string CallContextKey = "IncludeScopKey"; 

    private object oldValue; 

    public IncludeScope(IDictionary<string,int> values) 
    { 
     this.oldValue = CallContext.GetData(CallContextKey); 
     this.Includes = new Dictionary<string,int>(values); 
     CallContext.SetData(CallContextKey, this); 
    } 

    public Dictionary<string,int> Includes { get; private set; } 

    public static IncludeScope Current { 
     get { return CallContext.GetData(CallContextKey) as IncludeScope; } 
    } 

    private bool _disposed; 

    protected virtual bool IsDisposed 
    { 
     get 
     { 
      return _disposed; 
     } 
    } 

    ~IncludeScope() 
    { 
     Dispose(false); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!_disposed) { 
      if (disposing) { 
       CallContext.SetData(CallContextKey, oldValue); 
      } 
      _disposed = true; 
     } 
    } 
} 

범위를 다음과 같이 선언 할 수 있습니다.

using(var scope = new IncludeScope(new Dictionary<string,int>{{"Message",1}, {"Notifications",2}})){ 
    var query = await GetQueryAsync<User>(); 
    … 
} 

범위 내의 모든 메소드 호출에서 이와 같이 액세스 할 수 있습니다.

private static Task<IQueryable<T>> GetQueryAsync<T>() { 
    var baseQuery = context.Set<T>(); 
    foreach (var include in IncludeScope.Current.Includes) { 

    } 
} 
관련 문제