رفع خطای The LINQ expression could not be translated هنگام استفاده از دستور Contains
سلام دوستان یک پروژه در Asp.net Core 2.2 داشتم که یک کویری مشابه دستور زیر رو توش نوشته بودم و بدون هیچ خطایی اجرا می شه
public List<ProductViewModel> ProductListForSearch(int drpcourse = -1)
{
var Query = (from p in _context.Product_Tbl
select new ProductViewModel()
{
ProductID = p.ProductID,
ProductImage = p.ProductImage,
pGroupID = _context.ProductGroups_Tbl.Where(pg => pg.ProductID == p.ProductID).Select(s => s.GroupID).ToArray()
});
if (drpcourse != -1)
{
Query = Query.Where(c => c.pGroupID.Contains(drpcourse));
}
return Query.ToList();
}
همون طور که مشخصه در انتهای کویری بر اساس پارامتر drpcourse یک فیلتر انجام میشه. کلاس ProductViewModel هم به صورت زیر هست.
public class ProductViewModel
{
public int ProductID { get; set; }
public string ProductImage { get; set; }
public int[] pGroupID { get; set; }
}
حالا دقیقا این کویری رو میخوام در یک پروژه با Asp.net Core 3.1 که از Entity Framework 3.1 هم استفاده می کنه اجرا کنم اما خطای زیر رو میده:
InvalidOperationException: The LINQ expression 'DbSet<Product>
.Where(p => DbSet<ProductGroups>
.Where(p0 => p0.ProductID == p.ProductID)
.Select(p0 => p0.GroupID)
.ToArray()
.Contains(__drpcourse_0))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
لطفا راهنمایی کنید چرا در نسخه Core 2.2 این کویری اجرا میشه اما در نسخه 3.1 خطا داره ؟
پاسخ هوش مصنوعی
خطای شما به دلیل تغییرات در LINQ و Entity Framework در نسخه های جدیدتر است. در ASP.NET Core 3.1 و Entity Framework Core 3.1، برخی از قابلیت های LINQ به طور واضح نمی توانند به SQL ترجمه شوند، مانند این که شما یک آرایه از IDs را با استفاده از `Contains` در یک کویری به دست آمده از یک زیر پرس وجو مقایسه می کنید.
برای رفع این مشکل، می توانید به جای تبدیل لیست به آرایه و استفاده از `Contains`، مستقیماً از `Any()` استفاده کنید. کد شما به صورت زیر اصلاح می شود:
public List<ProductViewModel> ProductListForSearch(int drpcourse = -1)
{
var Query = (from p in _context.Product_Tbl
select new ProductViewModel()
{
ProductID = p.ProductID,
ProductImage = p.ProductImage,
pGroupID = _context.ProductGroups_Tbl.Where(pg => pg.ProductID == p.ProductID).Select(s => s.GroupID).ToArray()
});
if (drpcourse != -1)
{
Query = Query.Where(c => c.pGroupID.Any(id => id == drpcourse));
}
return Query.ToList();
}
با این تغییر، خطا برطرف خواهد شد و کویری شما در ASP.NET Core 3.1 به درستی کار خواهد کرد.
استفاده از دستور Contains در انتیتی فریم ورک 3.1
خطایی که شما دارید به این خاطر هست که در انتیتی فریم ورک نسخه 3.0 به بعد نسبت به انتیتی فریم ورک 2.2 تغییراتی وجود داشته. دستور زیر رو که شما در Core 2.2 استفاده می کردید و به درستی هم جواب میداده رو در نظر بگیرید :
Query = Query.Where(c => c.pGroupID.Contains(drpcourse));
خب در این دستور همه اطلاعات از دیتابیس واکشی شده و به روی سرور منتقل میشه و در سرور با توجه به دستور Contains اطلاعات فیلتر میشه و خروجی نمایش داده میشه. این چیزی هست که در Core 2.2 انجام میشه. اما یک اشکال داره و اونم این هست که باید همه اطلاعات به سرور بیاد و در سرور فیلتر بشه و خروجی مورد نظر نمایش داده بشه. خب این جا بار اضافی داره بر روی سرور تحمیل میشه. در انتیتی فریم ورک نسخه 3.0 به بعد برای این مشکل راه حل دادن و دلیل خطای شما هم همین هست.
در انتیتی فریم ورک نسخه 3.0 به بعد client evaluation پشتیبانی نمیشه. یعنی اطلاعات رو نمیشه فرستاد روی سرور و حافظه سرور و بعد جستجو کرد.
استفاده از متد AsEnumerable در انتیتی فریم ورک
اما راه حلی که در انتیتی فریم ورم 3.0 به بعد برای استفاده از متد Contains وجود داره این هست که از متد AsEnumerable استفاده بشه. وقتی از این متد استفاده می کنید کوئری شما در سمت دیتابیس اجرا میشه و فقط نتیجه به سمت سرور برگردانده میشه. این روش بازدهی بسیار بهتری در داده های زیاد دارد.
در نتیجه کوئری شما به این شکل باید تغییر کنه
public List<ProductViewModel> ProductListForSearch(int drpcourse = -1)
{
var Query = (from p in _context.Product_Tbl
select new ProductViewModel()
{
ProductID = p.ProductID,
ProductImage = p.ProductImage,
pGroupID = _context.ProductGroups_Tbl.Where(pg => pg.ProductID == p.ProductID).Select(s => s.GroupID).ToArray()
}).AsEnumerable();
if (drpcourse != -1)
{
Query = Query.Where(c => c.pGroupID.Contains(drpcourse));
}
return Query.ToList();
}
- آموزش استفاده از پلاگین گردونه شانس در Asp.net core به همراه سورس
- نمایش متن به صورت فرمت شده در CkEditor
- آموزش استفاده از SignalR در Asp.net Core با مثال عملی
- ادغام چند گزارش استیمول سافت بصورت پی دی اف در یک فایل
- نحوه تغییر استایل کامپوننت select2 چگونه است ؟
- چگونه امنیت پروژه را در Asp.net Core افزایش دهیم ؟
- ارسال پارامتر در دستور window.open جی کویری
- ارسال پارامتر از طریق جاوااسکریپت با کلیک روی تگ a
- خطای 500 زمان اجرا شدن پروژه روی هاست
- کویری نویسی در استیمول سافت جهت فیلتر اطلاعات
- کار با CkEditor با قابلیت آپلود عکس
- خطا در ایجاد migration در Asp.net core
- مشکل تاریخ شمسی در سی شارپ
- تفاوت های Asp.net core و Asp.net mvc چیه؟
- دلیل اسپم شدن ایمیل های ارسالی از سرور
- نحوه لایه بندی پروژه Core و اضافه کردن به IIS
- ارسال ایمیل در Asp.net core
- آیا میشه در mvc core از کامپونت استفاده کرد
- نمایش گزارش stimulsoft روی کلاینت
- آپلود فایل در Asp.net core چگونه است؟