1

私はC#を使用してファイルダウンロードサービスを構築しているところです。プロセスの一部で、1つ以上のデータベースからのダウンロードを検証し、ダウンロードの詳細を提供します。

検証プロセスが呼び出すことができるデータベースは4つあります。これは、ダウンロードの対象となるサービスによって異なります。データベースはMSSQLまたはMySQLのいずれかであり、(複合タイプの)ストアドプロシージャまたは複数の結合を持つLINQクエリのいずれかを使用できます。すべての結果には同じ列情報が含まれます。

Entity Framework内でデータベースを定義しましたが、単一のインスタンスのコードに満足しています。別のデータベースにクエリを実行した場合、同じタスクを実行するコードを再度記述したくありません。

条件に基づいて使用するエンティティとクエリを指定し、それを強く型付けしておくことができる解決策を見つけるために、数時間検索しました。

ストアドプロシージャクエリでは、次のようなコードを使用しています。

using (myEntity1 ctx = new myEntity1())
{
    var results = ctx.MyStoredProcedure(param1, param2);

    foreach (var result in results)
    {
        // do stuff here
    }
}

LINQクエリの場合、次のようなコードを使用できます。

using (myEntity2 ctx = new myEntity2())
{
    var results = (from t in ctx.table select new { t.Col1, t.Col2,});

    foreach (var result in results)
    {
        // do stuff here
    }
}

一言で言えば、いくつかの条件に基づいてエンティティとクエリを指定できるようにしたいと思います。また、結果を強く型付けする必要があります。簡単そうに見えますが、うまくいく答えが見つかりません。

ありがとう

クリス

4

1 に答える 1

0

もう 1 年間ノンストップで学習した後、今これを行っているとしたら、おそらくリポジトリを使用して各データセットをその POCO にロードし、これらの POCO を実際に必要な 1 つに投影するでしょう。おそらく次の拡張メソッドを使用します。

public static class QueryableExtensions
{

    public static ProjectionExpression<TSource> Project<TSource>(this IQueryable<TSource> source)
    {
        return new ProjectionExpression<TSource>(source);
    }

    public static string GetSQL<TSource>(this IQueryable<TSource> source)
    {
        return source.ToString();
    }
}

public class ProjectionExpression<TSource>
{
    private static readonly Dictionary<string, Expression> ExpressionCache = new Dictionary<string, Expression>();

    private readonly IQueryable<TSource> _source;

    public ProjectionExpression(IQueryable<TSource> source)
    {
        _source = source;
    }

    public IQueryable<TDest> To<TDest>()
    {
        var queryExpression = GetCachedExpression<TDest>() ?? BuildExpression<TDest>();

        return _source.Select(queryExpression);
    }

    private static Expression<Func<TSource, TDest>> GetCachedExpression<TDest>()
    {
        var key = GetCacheKey<TDest>();

        return ExpressionCache.ContainsKey(key) ? ExpressionCache[key] as Expression<Func<TSource, TDest>> : null;
    }

    private static Expression<Func<TSource, TDest>> BuildExpression<TDest>()
    {
        var sourceProperties = typeof(TSource).GetProperties();
        var destinationProperties = typeof(TDest).GetProperties().Where(dest => dest.CanWrite);
        var parameterExpression = Expression.Parameter(typeof(TSource), "src");


        var bindings = destinationProperties
                            .Select(destinationProperty => BuildBinding(parameterExpression, destinationProperty, sourceProperties))
                            .Where(binding => binding != null);

        var expression = Expression.Lambda<Func<TSource, TDest>>(Expression.MemberInit(Expression.New(typeof(TDest)), bindings), parameterExpression);

        var key = GetCacheKey<TDest>();

        ExpressionCache.Add(key, expression);

        return expression;
    }

    private static MemberAssignment BuildBinding(Expression parameterExpression, MemberInfo destinationProperty, IEnumerable<PropertyInfo> sourceProperties)
    {
        var sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == destinationProperty.Name);

        if (sourceProperty != null)
        {
            return Expression.Bind(destinationProperty, Expression.Property(parameterExpression, sourceProperty));
        }

        var propertyNames = SplitCamelCase(destinationProperty.Name);

        if (propertyNames.Length == 2)
        {
            sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == propertyNames[0]);

            if (sourceProperty != null)
            {
                var sourceChildProperty = sourceProperty.PropertyType.GetProperties().FirstOrDefault(src => src.Name == propertyNames[1]);

                if (sourceChildProperty != null)
                {
                    return Expression.Bind(destinationProperty, Expression.Property(Expression.Property(parameterExpression, sourceProperty), sourceChildProperty));
                }
            }
        }

        return null;
    }

    private static string GetCacheKey<TDest>()
    {
        return string.Concat(typeof(TSource).FullName, typeof(TDest).FullName);
    }

    private static string[] SplitCamelCase(string input)
    {
        return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim().Split(' ');
    }
}

http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code

于 2013-05-25T21:11:00.370 に答える