Saya sedang mengerjakan sebuah proyek dan saya mendapat kesalahan saat mendapatkan daftar pertanyaan. Saya akan memberi tahu pada blok kode di bawah ini.

//AT REPOSITORY SIDE THIS FUNCTION GETS FILTERED LIST OF RECORDS
        public List<TEntity> GetList(Expression<Func<TEntity, bool>> filter)
        {
            using (var context=new MyContext()){
                return context.Set<TEntity>().Where(filter).ToList();
            }
        }
//AT ENTITY SIDE THIS FUNCTION CHECKS IF ALL PROPERTIES ARE EQUAL WITH THE GIVEN OBJECT
        public bool PublicPropertiesEqual(object which) 
        {
            var type = this.GetType();
            var whichType = which.GetType();
            var whichProperties = whichType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if(whichProperties.Any(x => x.Name == pi.Name)){
                    object selfValue = type.GetProperty(pi.Name).GetValue(this, null);
                    object whichValue = type.GetProperty(pi.Name).GetValue(which,null);
                    if (selfValue != whichValue && (selfValue == null || !selfValue.Equals(whichValue)))
                    {
                        return false;
                    }
                }
            }
            return true;
        }
//AT CONTROLLER SIDE ONLY CALLED REPO GETLIST FUNCTION WITH GIVEN FILTER
        [HttpGet]
        public IActionResult GetList([FromQuery] TEntity  query)
        {
            List<TEntity> res = _repo.GetList(x = x.PublicPropertiesEqual(query));
            return Ok(res);
        }

MASALAH

Ketika saya menjalankan kode saya mendapatkan kesalahan seperti itu

InvalidOperationException: Ekspresi LINQ 'DbSet() .Where(c => c.PublicPropertiesEqual(__query_0))' tidak dapat diterjemahkan. Tulis ulang kueri dalam bentuk yang dapat diterjemahkan, atau alihkan ke evaluasi klien secara eksplisit dengan menyisipkan panggilan ke 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', atau 'ToListAsync'. Lihat https://go.microsoft.com/fwlink/?linkid=2101038 untuk informasi lebih lanjut.

Jadi saya tidak bisa mendapatkan catatan dari database. Saya mencoba menulis pohon ekspresi khusus yang ditunjukkan di bawah ini di sisi pengontrol dan itu juga tidak berfungsi.

        [HttpGet]
        public IActionResult GetList([FromQuery] TEntity  query)
        {
            var param = Expression.Parameter(typeof(TEntity));
            var lambda = Expression.Lambda<Func<TEntity,bool>>(
                Expression.Call(
                    param, 
                    _entityType.GetMethod("PublicPropertiesEqual"),
                    Expression.Constant(query)
                ),
                param
            );
            List<TEntity> res = _repo.GetList(lambda);
            return Ok(res);
        }

Dan kesalahan setelah mengeksekusi kode ini

InvalidOperationException: Ekspresi LINQ 'DbSet() .Where(c => c.PublicPropertiesEqual(Customer))' tidak dapat diterjemahkan. KESALAHANNYA SAMA DI ATAS...

Sebagai kesimpulan, bagaimana cara memfilter kueri dengan menggunakan fungsi PublicPropertiesEqual(object) ?

0
NoStuff 12 Mei 2021, 16:08

1 menjawab

Jawaban Terbaik

Sangat mudah untuk menulis fungsi seperti itu, tetapi Anda harus memfilter sendiri properti navigasi:

public static Expression<Func<T, bool>> PublicPropertiesEqual<T>(T entity)
{
    var props = typeof(T).GetProperties();
    var entityParam = Expression.Parameter(typeof(T), "e");
    var entityExpr = Expression.Constant(entity);

    var equality = props.Select(p => Expression.Equal(
        Expression.MakeMemberAccess(entityParam, p),
        Expression.MakeMemberAccess(entityExpr, p)
    ));

    var predicate = equality.Aggregate(Expression.AndAlso);
    return Expression.Lambda<Func<T, bool>>(predicate, entityParam);
}

Penggunaannya sederhana:

List<TEntity> res = _repo.GetList(PublicPropertiesEqual(query));

Pokoknya jika Anda memiliki akses ke DbContext lebih baik meneruskannya ke fungsi dan menggunakan kembali informasi IModel.

public static Expression<Func<T, bool>> PublicPropertiesEqual<T>(DbContext ctx, T entity)
{
    var et = ctx.Model.FindEntityType(typeof(T));
    if (et == null)
        throw new InvalidOperationException();

    var props = et.GetProperties();
    var entityParam = Expression.Parameter(typeof(T), "e");
    var entityExpr = Expression.Constant(entity);

    var equality = props
        .Where(p => !p.IsForeignKey() && !p.IsIndexerProperty())
        .Select(p => Expression.Equal(
            Expression.MakeMemberAccess(entityParam, p.PropertyInfo),
            Expression.MakeMemberAccess(entityExpr, p.PropertyInfo)
        ));

    var predicate = equality.Aggregate(Expression.AndAlso);
    return Expression.Lambda<Func<T, bool>>(predicate, entityParam);
}
1
Svyatoslav Danyliv 12 Mei 2021, 13:51