चूंकि मैं एक आलसी कुत्ता हूं, इसलिए मैं .net FluentValidation के लिए एक सामान्य UniqueValidator लागू करना चाहता हूं। लक्ष्य सरल है: एक सत्यापनकर्ता है जिसके लिए मैं मॉडल पास करता हूं, संपत्ति/फ़ील्ड प्राप्त करने के लिए अभिव्यक्ति जो अद्वितीय होनी चाहिए और एक ईएफ Any क्वेरी चलाएं। यह हर बार डीबी में एक मूल्य की एकता को सत्यापित करने के लिए एक गूंगा वर्ग लिखने से बच जाएगा।

मैं कुछ बदलावों के बाद आया था जो मुझे ईएफ क्वेरी अनुवादक के लिए एक पूर्व-संकलित लैम्ब्डा को पारित करने और लागू करने से बचने के लिए एक उचित समाधान लगता है, जिसके परिणामस्वरूप निश्चित रूप से expression could not be translated अपवाद होगा।

यहां मैंने जो कार्यान्वित किया है:

public class UniqueValidator : IUniqueValidator
{
    private ApplicationContext _dbContext;

    public UniqueValidator(ApplicationContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<bool> IsUnique<T>(T model, Expression<Func<T, string>> expression, CancellationToken cancellationToken) where T : class
    {
        // Getting the value to check for unicity:
        Func<T, string> method = expression.Compile(true);
        var value = method(model);

        // For GetDbSet<T>() test purpose, run perfectly:
        bool test = await GetDbSet<T>().OfType<BL.Driver>().AnyAsync(d => d.Email == "any.valid@email.com");


        // Building Linq expression
        var binaryExpression = Expression.Equal(expression.Body, Expression.Constant(value));
        var pe = new ParameterExpression[] { Expression.Parameter(typeof(T)) };

        var anyExpression = Expression.Lambda<Func<T, bool>>(binaryExpression, pe);

        return !(await GetDbSet<T>().AnyAsync(anyExpression));
    }

    private DbSet<T> GetDbSet<T>() where T : class
    {
        return (DbSet<T>)typeof(ApplicationContext)
            .GetProperties()
            .FirstOrDefault(p => p.PropertyType == typeof(DbSet<T>))
            .GetValue(_dbContext);
    }
}

यहां बताया गया है कि सत्यापनकर्ता का उपयोग कैसे किया जाता है:

RuleFor(d => d)
    .MustAsync((driver, cancellationToken) => {
        return uv.IsUnique(driver, d => d.Email, cancellationToken);
    });

दुर्भाग्य से यह एक बहुत ही बोझिल और उपयोगी अपवाद नहीं है:

System.InvalidOperationException: The LINQ expression 'DbSet<Driver>() .Any(d => d.Email == "any.valid@email.com")' could not be translated...

नोट: UniqueValidator कार्यान्वयन में मैंने अपवाद में वर्णित इसी क्वेरी का परीक्षण करने के लिए एक पंक्ति जोड़ी है और यह क्वेरी वैधता पर किसी भी संदेह को दूर करने के लिए पूरी तरह से चलती है।

मुझे लगता है कि समस्या expression.Body के अनुवाद के साथ है, लेकिन इसका कोई कारण नहीं दिख रहा है और न ही इसे कैसे हल किया जाए। किसी भी सहायता की सराहना की जाएगी।

0
Piou 4 जिंदा 2021, 21:54
1
आपके GetDbSet को DbContext.Set<T>() docs.microsoft.com/en-us/dotnet/api/…
 – 
David Browne - Microsoft
4 जिंदा 2021, 22:12
@ डेविड ब्राउन-माइक्रोसॉफ्ट वास्तव में प्रदर्शन के लिए मदद करता है लेकिन इससे समस्या का समाधान नहीं होता है, वैसे भी धन्यवाद।
 – 
Piou
4 जिंदा 2021, 22:16
1
इसलिए यह एक टिप्पणी है। मैंने बहुत पहले अभिव्यक्ति प्रश्नों का उपयोग करके गतिशील LINQ की धारा का उत्तर देने का प्रयास करना बंद कर दिया है।
 – 
David Browne - Microsoft
4 जिंदा 2021, 22:20
हाँ, मैं समझ गया, केवल अन्य पाठकों और भावी पीढ़ी के लिए इसका उल्लेख किया है :)
 – 
Piou
4 जिंदा 2021, 22:22

1 उत्तर

सबसे बढ़िया उत्तर

आपको अभिव्यक्ति के मूल पैरामीटर का पुन: उपयोग करना होगा, या आपको अभिव्यक्ति प्रतिकृति का उपयोग करना होगा:

var pe = new ParameterExpression[] { Expression.Parameter(typeof(T)) };

में बदलो

var pe = expression.Parameters[0];
1
xanatos 4 जिंदा 2021, 22:55