خطای "LINQ to Entities only supports casting EDM primitive types"


۲ سال پیش جمعه ۱۹ شهریور ۱۳۹۵ ساعت ۱۹:۱۰

فرض کنید می‌خواهید تابعی مثل تابع GetOrderBy را در یک کلاس کلی برای دریافت لیستی مرتب از یک موجودیت با استفاده از عبارت لامبدا تعریف
کنید.

public abstract class GenericRepository: IRepository
 where TEntity : class
{

protected readonly IUnitOfWork _uow;
protected readonly IDbSet _entity;

public GenericRepository(IUnitOfWork uow)
{
_uow = uow;
_entity = _uow.Set();
}

public IList GetOrderBy(Expression<Func<TEntity, object>> OrderByKeySelector)
{
return _entity.OrderBy(OrderByKeySelector).ToList();
}
}

شما می‌توانید به اینصورت از تابع بالا استفاده کنید:

Expression<Func<TEntity, object>> OrderByKeySelector = x=> x.CreatedOn;
_repo.GetOrderBy(OrderByKeySelector);

تا این مرحله شما هیچ خطایی دریافت نمی‌کنید اما بعد از دیباگ کردن با runtime error زیر مواجه می‌شوید:

Unable to cast the type 'System.DateTime' to type 'System.Object'.
LINQ to Entities only supports casting EDM primitive or enumeration types.

علت رخ دادن این خطا ارسال یک object به عنوان کلیدی برای مرتب سازی به تابع OrderBy است که type آن مشخص نیست برای حل این مشکل کافی بجای object به عنوان کلید مرتب سازی از نوع (type) دقیق آن کلیدی که بر اساس آن می‌خواهیم مرتب سازی کنیم استفاده کنیم.
در مثال بالا نوع خاصیت CreatedOn از DateTime هست برای رفع مشکل ذکر شده کافیست تابع GetOrderBy بصورت زیر اصلاح شود:

public IList GetOrderBy(Expression<Func<TEntity, DateTime>> OrderByKeySelector)
{
return _entity.OrderBy(OrderByKeySelector).ToList();
}

اما این نوع پیاده‌سازی، تابع GetOrderBy را محدود به مرتب سازی براساس کلیدهایی می‌کند که از نوع DateTime هستن برای حل این مشکل کافیست تابع GetOrderBy بصورت جنریک تعریف کنیم:

public IList GetOrderBy<TKey>(Expression<Func<TEntity, TKey>> OrderByKeySelector)
{
return _entity.OrderBy(OrderByKeySelector).ToList();
}

حالا نوع TKey قبل از اجرا شدن تابع GetOrderBy مشخص شده و تابع OrderBy بدون هیچ مشکلی اجرا می‌شود.

نوشتن نظر
سعيد - ۲۹ ماه و ۲۱ روز قبل
يك سؤال: استفاده از اين متد دقيقا چه نفعي داره؟ منظورم همين متد داخل Generic repository هست. اگر نبود چي ميشد؟ الان به چه مزيتي رسيديد؟ به نظر شما الان كدها زشت نشدن؟ همون طوري معمولي نوشته مي‌شد ايرادي داشت؟ اين همه پيچيدگي كه اعمال كرديد دقيقا قرار هست كجا مفيد واقع بشه؟
سید محمدرضا برنتی - ۲۹ ماه و ۲۱ روز قبل
خب این یه متد بسیار ساده‌است که در عمل هیچ وقت از آن استفاده نمیشه و اما به خوبی با استفاده از اون می‌شه علت خطا ذکر شده رو توضیح داد. بصورت کلی Generic repository سفارشی شما می‌تونه شامل متدهایی باشه که با یک ساختار ثابت در اکثر سرویس‌های شما پیاده‌سازی میشه و بعد می‌تونید با مشتق کردن اون سرویس‌ها از این Generic repository ، از نوشتن کدهای تکراری در سرویس‌های برنامه‌تان جلوگیری کنید. به عنوان مثال من توی سرویس‌های یک وب اپلیکیشن نیازمند متدی بودم که شماره صفحه و سایز صفحه و نوع مرتب سازی موجودیت اون سرویس رو گرفته و لیستی از موجودیت‌های مورد نظر رو برگرد، بجای اینکه یک تابع تکراری رو در سرویس‌های مختلف بنویسم و با توجه به موجودیت خاص اون سرویس اون تابع رو سفارشی کنم، برای یکبار این تابع رو در یک Generic repository پیاده‌سازی کردم و بعد سرویس‌هایی که به پیاده‌سازی اون تابع نیاز داشتن رو ازش مشتق کردم.
* من از ایمیل شما برای نمایش تصویر شما توسط سرویس gravatar استفاده خواهم کرد. من هم مثل شما از اسپم متنفرم.