0

より一般的な使用法を示すように例を更新しました。

ユーザー提供のローカリゼーションを許可するエンティティがあります。

public class ResourceValue
{
    public int ResourceValueId { get; set; }
    public string EnglishValue { get; set; }
    public string FrenchValue { get; set; }
    public string SpanishValue { get; set; }
    etc...
}

次のような他の多くのエンティティで使用されます。

public class SomeEntity
{
    public int Id { get; set; }
    public virtual ResourceValue Name { get; set; }
    public virtual ResourceValue ShortDescription { get; set; }
    public virtual ResourceValue LongDescription { get; set; }
    etc...
}

私はこのようなことをしたいと思います:

return context.SomeEntities.OrderBy(x => x.Name);

そして、私がこれをしたかのようにそれを機能させます:

return context.SomeEntities.OrderBy(x => x.Name.FrenchValue);

「fr-CA」である CurrentUICulture に基づいています。

Marc Gravell の回答 ( https://stackoverflow.com/a/1231941 ) に基づいていくつかのことを試してみましたが、私が望むものを完全に得ることができませんでした。

更新 - これはかなり近いですが、エンドコーダーが特別な考慮なしで使用できるように、単に「OrderBy」という名前を付けたいと思います。

    public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
    {
        return ApplyLocalizedOrder(source, keySelector, "OrderBy");
    }

    public static IOrderedQueryable<TSource> ApplyLocalizedOrder<TSource, TKey>(IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, string methodName)
    {
        ParameterExpression arg = keySelector.Parameters[0];
        Expression expr = Expression.PropertyOrField(keySelector.Body, GetCurrentCulture());
        LambdaExpression lambda = Expression.Lambda<Func<TSource, string>>(expr, arg);

        return (IOrderedQueryable<TSource>)typeof(Queryable).GetMethods().Single(
                method => method.Name == methodName
                        && method.IsGenericMethodDefinition
                        && method.GetGenericArguments().Length == 2
                        && method.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(TSource), expr.Type)
                .Invoke(null, new object[] { source, lambda });
    }
4

2 に答える 2

0

ラムダ式を動的に作成するのはクールですが、クエリの上に並べ替えを適用するメソッドを作成するだけで、はるかに簡単な方法で結果を得ることができます。メソッドは次のようになります。

    private static IQueryable<SomeEntity> OrderByName(IQueryable<SomeEntity> source, string culture)
    {
        if (culture == "fr-CA")
        {
            return source.OrderBy(x => x.Name.FrenchValue);
        }

        return source.OrderBy(x => x.Name.EnglishValue);
    }

そして、次のように使用します。

OrderByName(context.SomeEntities, "en-US")

例全体を次に示します。

public class MyCtx1 : DbContext
{
    public DbSet<SomeEntity> SomeEntities { get; set; }
    public DbSet<ResourceValue> ResourceValues { get; set; }
}

public class SomeEntity
{
    public int Id { get; set; }
    public virtual ResourceValue Name { get; set; }
}

public class ResourceValue
{
    public int ResourceValueId { get; set; }
    public string EnglishValue { get; set; }
    public string FrenchValue { get; set; }
}

class Program
{

    private static IQueryable<SomeEntity> OrderByName(IQueryable<SomeEntity> source, string culture)
    {
        if (culture == "fr-CA")
        {
            return source.OrderBy(x => x.Name.FrenchValue);
        }

        return source.OrderBy(x => x.Name.EnglishValue);
    }

    static void Main(string[] args)
    {
        using (var context = new MyCtx1())
        {
            if (!context.SomeEntities.Any())
            {
                context.SomeEntities.Add(
                    new SomeEntity() 
                    { 
                        Name = new ResourceValue()
                        {
                            EnglishValue = "abc - en",
                            FrenchValue = "xyz - fr"
                        }
                    });

                context.SomeEntities.Add(
                    new SomeEntity() 
                    { 
                        Name = new ResourceValue()
                        {
                            EnglishValue = "xyz - en",
                            FrenchValue = "abc - fr"
                        }
                    });

                context.SaveChanges();
            }

            Console.WriteLine("Ordered by english name");
            DisplayResults(OrderByName(context.SomeEntities, "en-US"));

            Console.WriteLine("Ordered by french name");
            DisplayResults(OrderByName(context.SomeEntities, "fr-CA"));
        }
    }

    private static void DisplayResults(IQueryable<SomeEntity> q)
    {
        foreach (var e in q)
        {
            Console.WriteLine(e.Id);
        }                
    }

そして結果:

Ordered by english name
1
2
Ordered by french name
2
1
Press any key to continue . . .
于 2012-09-19T19:54:23.293 に答える
0
context.SomeEntities.Select(v => v.Name.FrenchName).OrderBy(x => x);

しかし、getfor 名でそれよりもさらに優れているのは、現在のカルチャまたは特定のカルチャ、またはコードが呼び出しているものは何でも返すことです。クラスが実行できる場合に、Linq クエリでそれを実行する理由はありません。クラスで実行すると、コードを呼び出す場所で正しいカルチャが返されるため、とにかく優れています。

于 2013-01-09T03:19:00.817 に答える