Вот пара методов расширения, которые я пристроил присяжными для преобразования IQueryables и IEnumerables из одного типа в другой (т. Е. DTO). Он в основном используется для преобразования из большего типа (то есть типа строки в базе данных, в которой есть ненужные поля) в меньший.
Положительные стороны этого подхода:
- для его использования практически не требуется код - простой вызов .Transform
<DtoType>
() - это все, что вам нужно
- он работает так же, как .Select (s => new {...}), т. Е. При использовании с IQueryable он создает оптимальный код SQL, исключая поля Type1, которых у DtoType нет.
LinqHelper.cs:
public static IQueryable<TResult> Transform<TResult>(this IQueryable source)
{
var resultType = typeof(TResult);
var resultProperties = resultType.GetProperties().Where(p => p.CanWrite);
ParameterExpression s = Expression.Parameter(source.ElementType, "s");
var memberBindings =
resultProperties.Select(p =>
Expression.Bind(typeof(TResult).GetMember(p.Name)[0], Expression.Property(s, p.Name))).OfType<MemberBinding>();
Expression memberInit = Expression.MemberInit(
Expression.New(typeof(TResult)),
memberBindings
);
var memberInitLambda = Expression.Lambda(memberInit, s);
var typeArgs = new[]
{
source.ElementType,
memberInit.Type
};
var mc = Expression.Call(typeof(Queryable), "Select", typeArgs, source.Expression, memberInitLambda);
var query = source.Provider.CreateQuery<TResult>(mc);
return query;
}
public static IEnumerable<TResult> Transform<TResult>(this IEnumerable source)
{
return source.AsQueryable().Transform<TResult>();
}