একটি # স্ট্রিং হিসাবে সম্পত্তি নাম ব্যবহার করে কোনও সম্পত্তি অর্ডার করার জন্য কোড # কোড


92

আমার কাছে স্ট্রিং হিসাবে সম্পত্তির নাম থাকলে সি # তে কোনও সম্পত্তির বিরুদ্ধে কোড দেওয়ার সহজতম উপায় কী? উদাহরণস্বরূপ, আমি ব্যবহারকারীকে তাদের পছন্দসই সম্পত্তি (লিনকিউ ব্যবহার করে) কিছু অনুসন্ধান ফলাফল অর্ডার করার অনুমতি দিতে চাই। তারা ইউআইতে "অর্ডার বাই" সম্পত্তিটি বেছে নেবে - অবশ্যই স্ট্রিংয়ের মান হিসাবে। লিংক ক্যোয়ারির সম্পত্তি হিসাবে সরাসরি স্ট্রিংটি ব্যবহার করার উপায় আছে কি না শর্তাধীন যুক্তি (যদি / অন্যথায় স্যুইচ) ব্যবহার না করে বৈশিষ্ট্যগুলিতে স্ট্রিংগুলি ম্যাপ করতে হয়। প্রতিবিম্ব?

যৌক্তিকভাবে, আমি এটি করতে চাই:

query = query.OrderBy(x => x."ProductId");

আপডেট: আমি মূলত সুনির্দিষ্টভাবে উল্লেখ করেছিলাম না যে আমি লিনককে সত্তা থেকে ব্যবহার করছি - এটি প্রদর্শিত হয় যে প্রতিবিম্ব (কমপক্ষে গেটপ্রপার্টি, গেটভ্যালু পদ্ধতির) L2E তে অনুবাদ করে না।


আমি মনে করি আপনাকে প্রতিবিম্ব ব্যবহার করতে হবে, এবং আমি নিশ্চিত না যে আপনি ল্যাম্বডা এক্সপ্রেশনটিতে প্রতিচ্ছবিটি ব্যবহার করতে পারবেন ... ভাল, লিনক থেকে এসকিউএল প্রায় নয় তবে সম্ভবত কোনও লিঙ্ক বা কোনও কিছুর বিপরীতে লিনক ব্যবহার করার সময়।
কোডরেডিক

@ টেলোস: কোনও ল্যাম্বডায় আপনি প্রতিবিম্ব (বা অন্য কোনও এপিআই) ব্যবহার করতে পারবেন না এমন কোনও কারণ নেই। কোডটি একটি অভিব্যক্তি হিসাবে মূল্যায়ন হয়ে অন্য কোনও কিছুর (যেমন লিনকিউ-টু-এসকিউএল যেমন আপনার পরামর্শ অনুসারে) অনুবাদ করা হয়ে থাকে তবে এটি কাজ করবে কিনা entire
অ্যাডাম রবিনসন

এই কারণেই আমি একটি উত্তরের পরিবর্তে একটি মন্তব্য পোস্ট করেছি। ;) লিঙ্ক 2 এসকিউএল এর বেশিরভাগ ক্ষেত্রে ব্যবহৃত হত ...
কোডরেডিক

4
ঠিক একই সমস্যাটি কাটিয়ে উঠতে হয়েছিল .. নীচে আমার উত্তরটি দেখুন। স্ট্যাকওভারফ্লো.com
মার্ক পাওয়েল

উত্তর:


129

বাকি সবাই যা পোস্ট করেছে আমি তার এই বিকল্পটির প্রস্তাব দেব।

System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");

query = query.OrderBy(x => prop.GetValue(x, null));

সম্পত্তি অর্জনের জন্য এটি প্রতিবিম্ব এপিআই-এর পুনরাবৃত্তি কলগুলি এড়িয়ে চলে। এখন কেবল পুনরাবৃত্তি কলটি মূল্য অর্জন করছে।

যাহোক

আমি PropertyDescriptorপরিবর্তে ব্যবহারের পক্ষে পরামর্শ দেব , কারণ এটি কাস্টমসগুলিকে TypeDescriptorআপনার ধরণের জন্য বরাদ্দ করার অনুমতি দেবে , যার ফলে বৈশিষ্ট্য এবং মানগুলি পুনরুদ্ধারের জন্য হালকা ওজনের ক্রিয়াকলাপ সম্ভব হবে। কোনও কাস্টম বর্ণনাকারীর অভাবে এটি কোনওভাবেই প্রতিচ্ছবিতে ফিরে আসবে।

PropertyDescriptor prop = TypeDescriptor.GetProperties(typeof(YourType)).Find("PropertyName");

query = query.OrderBy(x => prop.GetValue(x));

এটির গতি বাড়ানোর জন্য, HyperDescriptorকোডপ্রজেক্টে মার্ক গ্রেভেলের প্রকল্পটি দেখুন। আমি এটি দুর্দান্ত সাফল্যের সাথে ব্যবহার করেছি; এটি উচ্চ-পারফরম্যান্স ডেটা বাঁধাই এবং ব্যবসায়িক সামগ্রীতে গতিশীল সম্পত্তি ক্রিয়াকলাপের জন্য জীবন রক্ষাকারী।


দ্রষ্টব্য যে প্রতিফলিত প্রার্থনা (অর্থাত্ GetValue) প্রতিবিম্বের সবচেয়ে ব্যয়বহুল অংশ। মেটাডেটা পুনরুদ্ধার (অর্থাত্ গেটপ্রোপার্টি) আসলে কম ব্যয়বহুল (আকারের ক্রম দ্বারা), সুতরাং সেই অংশটি ক্যাশে করে, আপনি সত্যিকার অর্থে নিজেকে এতটা সাশ্রয় করছেন না। এটি উভয় উপায়ে বেশ একই রকম ব্যয় করতে চলেছে, এবং সেই ব্যয়টি ভারী হতে চলেছে। কিছু খেয়াল করার জন্য।
জ্রিস্টা

4
@ জ্রিস্টা: সুনিশ্চিত হওয়ার জন্য প্রার্থনা সবচেয়ে ব্যয়বহুল। তবে, "কম ব্যয়বহুল" এর অর্থ "ফ্রি" নয়, বা এটির কাছাকাছিও নয়। মেটাডাটা পুনরুদ্ধার একটি অ-তুচ্ছ পরিমাণ সময় নেয়, তাই এটি ক্যাশে করার সুবিধা রয়েছে এবং কোনও অসুবিধা নেই (যদি না আমি এখানে কিছু মিস করছি)। সত্য সত্যই এটি যে PropertyDescriptorকোনও উপায়ে ব্যবহার করা উচিত (কাস্টম ধরণের বর্ণনাকারীদের অ্যাকাউন্টে, যা মান পুনরুদ্ধারকে একটি হালকা ওজনের অপারেশন করতে পারে )।
অ্যাডাম রবিনসন

ASP.NET গ্রিডভিউ প্রোগ্রামগতভাবে বাছাইয়ের জন্য এমন কিছুর জন্য কয়েক ঘন্টার জন্য অনুসন্ধান করা হয়েছে: প্রপার্টিডেস্কিটার প্রোপ = টাইপডেস্কিটার.গেটপ্রোপার্টি (টাইপফ (স্কলারশিপআরেক্সেস্ট))। সন্ধান করুন (e.SortExpression, সত্য);
বাক্সটার

4
stackoverflow.com/questions/61635636/... এটা EfCore 3.1.3 আউট কাজ করে নি প্রতিফলন সঙ্গে একটি সমস্যা হয়েছে। এটি EFCore 2 এ ত্রুটি ফেলেছে বলে মনে হচ্ছে যা সতর্কতার জন্য সক্রিয় করা দরকার। নীচে @ মার্কের উত্তরটি ব্যবহার করুন
আর্মআরশিল্ড

4
আমি নিম্নলিখিতটি পেয়েছি: অবৈধ অপারেশন ধারণা: লিনকিউ এক্সপ্রেশন 'ডিবিসেট <মাইবজেক্ট> .কখন (t => t.IsMasterData) rdআর্ডারবি (t => t.GetType ()। গেটপোপার্টি ("ঠিকানা") Get গেটভ্যালিউ (আপত্তি: টি, সূচক: নাল) .গেটটাইপ ()) 'অনুবাদ করা যায়নি। হয় এমন কোনও ফর্মটিতে ক্যোয়ারীটি পুনর্লিখন করুন যা অনুবাদ করা যেতে পারে, বা AsEnumerable (), AsAsyncEnumerable (), ToList (), বা ToListAsync () এ কল সন্নিবেশ করে স্পষ্টভাবে ক্লায়েন্টের মূল্যায়নে স্যুইচ করুন।
ব্রিবঙ্ক

67

আমি পার্টিতে কিছুটা দেরি করেছি, তবে আমি আশা করি এটি কিছুটা সহায়ক হতে পারে।

প্রতিবিম্বটি ব্যবহার করে সমস্যাটি হ'ল ফলস্বরূপ অভিব্যক্তি গাছটি অবশ্যই অভ্যন্তরীণ। নেট সরবরাহকারী ব্যতীত অন্য কোনও লিঙ্ক সরবরাহকারী দ্বারা সমর্থিত হবে না। এটি অভ্যন্তরীণ সংগ্রহের জন্য সূক্ষ্ম, তবে পৃষ্ঠাগুলির পূর্বে যেখানে উত্স অনুসারে বাছাই করা হয় সেখানে এটি কাজ করবে না (যে এসকিউএল, মঙ্গোডিবি, ইত্যাদি)।

নীচের কোডের নমুনাটি অর্ডারবাই এবং অর্ডারবাইডেসেন্ডিংয়ের জন্য আইকোয়্যারেবল এক্সটেনশন পদ্ধতি সরবরাহ করে এবং এর মতো ব্যবহার করা যেতে পারে:

query = query.OrderBy("ProductId");

সম্প্রসারণ পদ্ধতি:

public static class IQueryableExtensions 
{
    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)
    {
        return source.OrderBy(ToLambda<T>(propertyName));
    }

    public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string propertyName)
    {
        return source.OrderByDescending(ToLambda<T>(propertyName));
    }

    private static Expression<Func<T, object>> ToLambda<T>(string propertyName)
    {
        var parameter = Expression.Parameter(typeof(T));
        var property = Expression.Property(parameter, propertyName);
        var propAsObject = Expression.Convert(property, typeof(object));

        return Expression.Lambda<Func<T, object>>(propAsObject, parameter);            
    }
}

শুভেচ্ছা, চিহ্ন।


দুর্দান্ত সমাধান - আমি ঠিক সেটাই খুঁজছিলাম। আমার সত্যিই এক্সপ্রেশন গাছগুলি খনন করা উচিত। তবুও খুব ছদ্মবেশী। @ মার্ক, নেস্টেড এক্সপ্রেশন করার কোনও সমাধান? বলুন আমার কাছে টাইপ টিএসব টাইপের "সাব" প্রপার্টি রয়েছে যা নিজেই একটি সম্পত্তি "মান" রয়েছে। এখন আমি "সাব.ভ্যালু" স্ট্রিংয়ের জন্য এক্সপ্রেশন <ফানক <টি, অবজেক্ট >> এক্সপ্রেশন পেতে চাই।
সাইমন শ্যাচারার

4
কেন Expression.Convertরূপান্তর propertyকরার জন্য আমাদের দরকার object? আমি একটি Unable to cast the type 'System.String' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.ত্রুটি পাচ্ছি , এবং অপসারণ এটি কাজ করে বলে মনে হচ্ছে।
শুবারফু

@ ডেমোডেভ যদি আমি সঠিকভাবে মনে করি var propAsObject = Expression.Convert(property, typeof(object));এবং কেবলমাত্র propertyজায়গায় ব্যবহার করুনpropAsObject
শুবারফু

সোনার। একটি নেট কোর 2.0.5।
ক্রিস আমলিংকেক্স

4
ত্রুটি পেয়েছেLINQ to Entities only supports casting EDM primitive or enumeration types
ম্যাটিউজ পুয়াভোস্কি

35

আমি @ মার্ক পাওয়েল থেকে উত্তরটি পছন্দ করেছি , তবে @ শুবারফু যেমন বলেছিলেন, এটি ত্রুটি দেয় LINQ to Entities only supports casting EDM primitive or enumeration types

অপসারণ var propAsObject = Expression.Convert(property, typeof(object));যেমন মান সংখ্যার মতো ধরণের বৈশিষ্ট্যগুলির সাথে কাজ করে না, কারণ এটি বস্তুর সাথে অন্তর্নিহিতভাবে বাক্স না দেয় n't

ক্রিস্টোফার অ্যান্ডারসন এবং মার্ক গ্র্যাভেলের আইডিয়াস ব্যবহার করে আমি সম্পত্তিটির নাম ব্যবহার করে ক্যোয়ারিয়েল ফাংশনটি তৈরির একটি উপায় খুঁজে পেয়েছি এবং এটি এখনও সত্তা ফ্রেমওয়ার্কের সাথে কাজ করে চলেছে। আমি একটি alচ্ছিক আইকম্পেরার প্যারামিটারও অন্তর্ভুক্ত করেছি। সতর্কতা: আইসিকম্পারার প্যারামিটার সত্তা ফ্রেমওয়ার্কের সাথে কাজ করে না এবং লিনক থেকে স্ক্যুয়াল ব্যবহার করে ছেড়ে দেওয়া উচিত।

অ্যান্টিটি ফ্রেমওয়ার্ক এবং লিনক থেকে এসকিএল এর সাথে নিম্নলিখিতগুলি কাজ করে:

query = query.OrderBy("ProductId");

এবং @ সিমন শিউচার এটিও কাজ করে:

query = query.OrderBy("ProductCategory.CategoryId");

এবং যদি আপনি সিকিএল থেকে সত্তা ফ্রেমওয়ার্ক বা লিনক ব্যবহার না করেন তবে এটি কাজ করে:

query = query.OrderBy("ProductCategory", comparer);

কোডটি এখানে:

public static class IQueryableExtensions 
{    
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
    return CallOrderedQueryable(query, "OrderBy", propertyName, comparer);
}

public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
    return CallOrderedQueryable(query, "OrderByDescending", propertyName, comparer);
}

public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
    return CallOrderedQueryable(query, "ThenBy", propertyName, comparer);
}

public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
    return CallOrderedQueryable(query, "ThenByDescending", propertyName, comparer);
}

/// <summary>
/// Builds the Queryable functions using a TSource property name.
/// </summary>
public static IOrderedQueryable<T> CallOrderedQueryable<T>(this IQueryable<T> query, string methodName, string propertyName,
        IComparer<object> comparer = null)
{
    var param = Expression.Parameter(typeof(T), "x");

    var body = propertyName.Split('.').Aggregate<string, Expression>(param, Expression.PropertyOrField);

    return comparer != null
        ? (IOrderedQueryable<T>)query.Provider.CreateQuery(
            Expression.Call(
                typeof(Queryable),
                methodName,
                new[] { typeof(T), body.Type },
                query.Expression,
                Expression.Lambda(body, param),
                Expression.Constant(comparer)
            )
        )
        : (IOrderedQueryable<T>)query.Provider.CreateQuery(
            Expression.Call(
                typeof(Queryable),
                methodName,
                new[] { typeof(T), body.Type },
                query.Expression,
                Expression.Lambda(body, param)
            )
        );
}
}

গীজ, মানুষ, তুমি কি মাইক্রোসফ্ট? :) যে Aggregateখণ্ডটি দুর্দান্ত! এটি EF কোর মডেল দিয়ে তৈরি ভার্চুয়াল ভিউগুলির যত্ন নেয় Join, যেহেতু আমি "টি.প্রপার্টি" এর মতো বৈশিষ্ট্য ব্যবহার করি। অন্যথায় পরে অর্ডার Joinকরা অসম্ভব হয় উত্পাদন InvalidOperationExceptionবা হয় NullReferenceException। এবং এরপরে আমার অর্ডার করা দরকার Join, কারণ বেশিরভাগ ক্যোরিয়াস ধ্রুবক, ভিউগুলিতে অর্ডার হয় না।
হ্যারি

@ হ্যারি ধন্যবাদ, তবে আমি খণ্ডটির জন্য খুব বেশি ক্রেডিট নিতে পারি না Aggregate। আমি বিশ্বাস করি এটি ছিল মার্ক গ্র্যাভেলের কোড এবং একটি ইন্টেলিসেন্সের সুপারিশের সংমিশ্রণ । :)
ডেভিড স্পেচট

@ ডেভিডস্পেট আমি কেবল এক্সপ্রেশন ট্রিগুলি শিখছি, সুতরাং এগুলি সম্পর্কে আমার কাছে এখনও কালো জাদু। তবে আমি দ্রুত শিখি, ভিএস-তে সি # ইন্টারেক্টিভ উইন্ডো অনেক সহায়তা করে।
হ্যারি

এটি কিভাবে ব্যবহার করবেন?
ডেটা

@ ডাট এনগুইন এর পরিবর্তে products.OrderBy(x => x.ProductId)আপনি ব্যবহার করতে পারেনproducts.OrderBy("ProductId")
ডেভিড

12

হ্যাঁ, আমি মনে করি না প্রতিবিম্ব ছাড়া অন্য উপায় আছে।

উদাহরণ:

query = query.OrderBy(x => x.GetType().GetProperty("ProductId").GetValue(x, null));

আমি ত্রুটি পেয়েছি "LINQ to Entities does not recognize the method 'System.Object GetValue(System.Object)' method, and this method cannot be translated into a store expression."কোন চিন্তা বা পরামর্শ, দয়া করে?
ফ্লোরিন ভার্ডোল

5
query = query.OrderBy(x => x.GetType().GetProperty("ProductId").GetValue(x, null));

আমার মাথার উপরের অংশ থেকে নিখুঁত বাক্য গঠন প্রত্যাহার করার চেষ্টা করছি তবে আমি মনে করি এটি সঠিক।


2

প্রতিবিম্বই উত্তর!

typeof(YourType).GetProperty("ProductId").GetValue(theInstance);

প্রতিবিম্বিত প্রপার্টি ইনফোর ক্যাশে, খারাপ স্ট্রিং পরীক্ষা করতে, আপনার ক্যোয়ারী তুলনা ফাংশন ইত্যাদি লিখতে আপনি অনেক কিছুই করতে পারেন তবে তার হৃদয়ে আপনি এটি করছেন।


2

আপনি গতিশীল লিনক ব্যবহার করতে পারেন - এই ব্লগটি দেখুন।

এছাড়াও চেক আউট এই Stackoverflow পোস্ট করুন ...


এটি আমার পক্ষে সেরা উত্তর
Demodave

2

গতিশীল অর্ডার আইটেমগুলিতে প্রতিবিম্ব এক্সটেনশনের চেয়ে বেশি উত্পাদনশীল:

public static class DynamicExtentions
{
    public static object GetPropertyDynamic<Tobj>(this Tobj self, string propertyName) where Tobj : class
    {
        var param = Expression.Parameter(typeof(Tobj), "value");
        var getter = Expression.Property(param, propertyName);
        var boxer = Expression.TypeAs(getter, typeof(object));
        var getPropValue = Expression.Lambda<Func<Tobj, object>>(boxer, param).Compile();            
        return getPropValue(self);
    }
}

উদাহরণ:

var ordered = items.OrderBy(x => x.GetPropertyDynamic("ProductId"));

এছাড়াও আপনার মেনে চলতে থাকা ল্যাম্বাস (যেমন অভিধানে <>)


1

এছাড়াও ডায়নামিক এক্সপ্রেশনগুলি এই সমস্যার সমাধান করতে পারে। আপনি লিনকিউ এক্সপ্রেশনগুলির মাধ্যমে স্ট্রিং-ভিত্তিক ক্যোয়ারীগুলি ব্যবহার করতে পারেন যা রান-টাইমে গতিশীলভাবে নির্মিত হতে পারে।

var query = query
          .Where("Category.CategoryName == @0 and Orders.Count >= @1", "Book", 10)
          .OrderBy("ProductId")
          .Select("new(ProductName as Name, Price)");

0

আমি মনে করি আমরা একটি শক্তিশালী সরঞ্জাম নাম এক্সপ্রেশন একটি ব্যবহার করতে পারি এই ক্ষেত্রে এটি এক্সটেনশন পদ্ধতি হিসাবে নিম্নলিখিত হিসাবে ব্যবহার করুন:

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, bool descending)
{
    var type = typeof(T);
    var property = type.GetProperty(ordering);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var orderByExp = Expression.Lambda(propertyAccess, parameter);
    MethodCallExpression resultExp = 
        Expression.Call(typeof(Queryable), (descending ? "OrderByDescending" : "OrderBy"), 
            new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
    return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(resultExp);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.