সংস্থাগুলি থেকে লিনকিউ কেবল ইডিটি ইন্টারফেসের সাথে EDM আদিম বা গণনা প্রকারের কাস্টিং সমর্থন করে


96

আমার নিম্নলিখিত জেনেরিক এক্সটেনশন পদ্ধতি রয়েছে:

public static T GetById<T>(this IQueryable<T> collection, Guid id) 
    where T : IEntity
{
    Expression<Func<T, bool>> predicate = e => e.Id == id;

    T entity;

    // Allow reporting more descriptive error messages.
    try
    {
        entity = collection.SingleOrDefault(predicate);
    }
    catch (Exception ex)
    {
        throw new InvalidOperationException(string.Format(
            "There was an error retrieving an {0} with id {1}. {2}",
            typeof(T).Name, id, ex.Message), ex);
    }

    if (entity == null)
    {
        throw new KeyNotFoundException(string.Format(
            "{0} with id {1} was not found.",
            typeof(T).Name, id));
    }

    return entity;
}

দুর্ভাগ্যক্রমে সত্তা ফ্রেমওয়ার্ক কীভাবে পরিচালনা করতে জানে না predicateযেহেতু সি # প্রিকেটটিকে নীচে রূপান্তরিত করে:

e => ((IEntity)e).Id == id

সত্তা ফ্রেমওয়ার্ক নিম্নলিখিত ব্যতিক্রম ছোঁড়ে:

'সামেরেন্টি' টাইপ করতে 'আইএনটিটি' টাইপ কাস্ট করতে অক্ষম। সংস্থাগুলিতে লিনকিউ কেবল ইডিএম আদিম বা গণনা প্রকারের castালাই সমর্থন করে।

কীভাবে আমরা আমাদের IEntityইন্টারফেসের সাথে সত্ত্বা ফ্রেমওয়ার্ককে কাজ করতে পারি ?

উত্তর:


189

আমি classএক্সটেনশন পদ্ধতিতে জেনেরিক ধরণের সীমাবদ্ধতা যোগ করে এটি সমাধান করতে সক্ষম হয়েছি । যদিও এটি কাজ করে তা আমি নিশ্চিত নই।

public static T GetById<T>(this IQueryable<T> collection, Guid id)
    where T : class, IEntity
{
    //...
}

6
আমার জন্য কাজ করে! আমি এই ব্যাখ্যা করতে সক্ষম হতে কেউ চাই। #linqblackmagic
বার্কো

আপনি দয়া করে ব্যাখ্যা করতে পারেন আপনি কীভাবে এই সীমাবদ্ধতা যুক্ত করেছিলেন
yrahman

5
আমার অনুমান যে ক্লাস টাইপটি ইন্টারফেস টাইপের পরিবর্তে ব্যবহৃত হয়। EF ইন্টারফেস টাইপ সম্পর্কে জানেন না তাই এটি এটিকে এসকিউএলে রূপান্তর করতে পারে না। শ্রেণীর সীমাবদ্ধতার সাথে অনুমিত টাইপটি হ'ল DbSet <T> টাইপ যা EF কী করতে হবে তা জানে।
jwize

4
পারফেক্ট, ইন্টারফেস-ভিত্তিক ক্যোয়ারীগুলি সম্পাদন করতে সক্ষম হওয়া এবং এখনও আইকোয়ারিযোগ্য হিসাবে সংগ্রহটি বজায় রাখতে সক্ষম। কিছুটা বিরক্তিকর যে EF এর অভ্যন্তরীণ কাজগুলি না জেনে মূলত এই ফিক্সটি চিন্তা করার কোনও উপায় নেই।
Anders

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

64

class"ফিক্স" সম্পর্কিত কিছু অতিরিক্ত ব্যাখ্যা ।

এই উত্তরটি দুটি ভিন্ন অভিব্যক্তি দেখায়, একটির সাথে এবং অন্যটি কোনও where T: classবাধা ছাড়াই । আমাদের classবাধা ছাড়া :

e => e.Id == id // becomes: Convert(e).Id == id

এবং সীমাবদ্ধতার সাথে:

e => e.Id == id // becomes: e.Id == id

এই দুটি এক্সপ্রেশন সত্তা কাঠামোর দ্বারা আলাদাভাবে আচরণ করা হয়। EF 6 উত্সের দিকে তাকালে , কেউ দেখতে পাবেন যে ব্যতিক্রমটি এখান থেকে এসেছে , দেখুনValidateAndAdjustCastTypes()

যা হয় তা হ'ল ইএফ IEntityএমন কোনও কিছুতে ফেলে দেওয়ার চেষ্টা করে যা ডোমেন মডেল ওয়ার্ল্ডকে বোঝায়, তবে এটি এটি করতে ব্যর্থ হয়, তাই ব্যতিক্রমটি ছুঁড়ে দেওয়া হয়।

classসীমাবদ্ধতার সাথে অভিব্যক্তিটিতে Convert()অপারেটর থাকে না , castালার চেষ্টা করা হয় না এবং সবকিছু ঠিক থাকে।

এটি এখনও খোলামেলা প্রশ্ন থেকেই যায়, লিনকিউ কেন বিভিন্ন অভিব্যক্তি তৈরি করে? আমি আশা করি কিছু সি # উইজার্ড এটি ব্যাখ্যা করতে সক্ষম হবে।


4
ব্যাখ্যার জন্য ধন্যবাদ.
জেস রিয়া

10
@ জনস্কিটে কেউ এখানে একটি সি # উইজার্ড ডেকে আনার চেষ্টা করেছেন। তুমি কোথায়?
নিক এন।

24

সত্তা ফ্রেমওয়ার্ক বাক্সের বাইরে এটি সমর্থন করে না, তবে ExpressionVisitorঅভিব্যক্তিটির অনুবাদ করে এমন একটি সহজেই লিখিত হয়:

private sealed class EntityCastRemoverVisitor : ExpressionVisitor
{
    public static Expression<Func<T, bool>> Convert<T>(
        Expression<Func<T, bool>> predicate)
    {
        var visitor = new EntityCastRemoverVisitor();

        var visitedExpression = visitor.Visit(predicate);

        return (Expression<Func<T, bool>>)visitedExpression;
    }

    protected override Expression VisitUnary(UnaryExpression node)
    {
        if (node.NodeType == ExpressionType.Convert && node.Type == typeof(IEntity))
        {
            return node.Operand;
        }

        return base.VisitUnary(node);
    }
}

আপনাকে কেবলমাত্র যা করতে হবে তা হ'ল এক্সপ্রেশন ভিজিটরটি ব্যবহার করে পাসিকেডে পাসটি রূপান্তর করা:

public static T GetById<T>(this IQueryable<T> collection, 
    Expression<Func<T, bool>> predicate, Guid id)
    where T : IEntity
{
    T entity;

    // Add this line!
    predicate = EntityCastRemoverVisitor.Convert(predicate);

    try
    {
        entity = collection.SingleOrDefault(predicate);
    }

    ...
}

অপর-নমনীয় - পদ্ধতির ব্যবহারটি হ'ল DbSet<T>.Find:

// NOTE: This is an extension method on DbSet<T> instead of IQueryable<T>
public static T GetById<T>(this DbSet<T> collection, Guid id) 
    where T : class, IEntity
{
    T entity;

    // Allow reporting more descriptive error messages.
    try
    {
        entity = collection.Find(id);
    }

    ...
}

1

আমার একই ত্রুটি কিন্তু একই রকম তবে ভিন্ন সমস্যা ছিল। আমি একটি এক্সটেনশান ফাংশন তৈরি করার চেষ্টা করছিলাম যা আইকুয়েরেবল ফিরিয়েছিল তবে ফিল্টার মানদণ্ডটি বেস শ্রেণীর উপর ভিত্তি করে ছিল।

আমি অবশেষে সমাধানটি পেয়েছিলাম যা আমার এক্সটেনশন পদ্ধতির জন্য কল করার জন্য ছিল S

সম্পূর্ণ বিবরণগুলি এখানে: আইএফসিএবারে <টি> EF- তে বেস ক্লাস ব্যবহার করে এক্সটেনশন তৈরি করুন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.