Search code examples
c#entity-frameworklinq-to-entities

MVC LINQ to Entities does not recognize the method call function - when to call function?


I am trying to call a function during the LINQ statement which obviously can't be translated to SQL. Here is my code, I am trying to convert a datetime to number of weeks. What is the best approach, do I loop through the data after and update the ViewModel?

Controller

public ActionResult Listings(string categoryName)
{
    HomeServices service = new HomeServices();

    return View(service.GetListingsViewModel(categoryName);
}

View Model

public class ResultsViewModel
{
    public System.Guid AdGuid { get; set; }
    public Nullable<System.DateTime> ListDate { get; set; }
    public string ListingAge { get; set; }
    public string Image1 { get; set; }

}
public class ListingsViewModel
{
    public IEnumerable<ResultsViewModel> ResultsVM { get; set; }
    public int TotalCount { get; set; }
}

Services

internal ListingsViewModel GetListingsViewModel(string categoryName)
{
    var listings = GetListingsVM(categoryName);
    var totalCount = listings.Count();

    return new ListingsViewModel()
    {
        ListingResultsVM = listings,
        TotalCount = totalCount
    };
}

internal IEnumerable<ResultsViewModel> GetListingsVM(string categoryName)
{
    var listings = Listings
      .Where(x => x.Category == categoryName)
      .Select(x => new ResultsViewModel
    {
        AdGuid = x.AdGuid,
        ListDate = x.ListDate,
        ListingAge = Logic.App.GetListingAge(x.BirthDate ?? DateTime.Now),
        Image1 = x.ListingImage.Image1
    });

    return listings;
}

Logic.App

public static string GetListingAge(System.DateTime varListDate)
{
    //Function code to convert DateTime to Weeks
    return functionReturnValue;
}

Solution

  • First, Download required data. Then, Locally manipulate it into requirements.

    var listings = Listings
      .Where(x => x.Category == categoryName)
      .Select(x => new 
      {
        AdGuid = x.AdGuid,
        ListDate = x.ListDate,
        Image1 = x.ListingImage.Image1
      })
      .AsEnumerable() // make call to DB
      .Select(x => new ResultsViewModel
      {
        AdGuid = x.AdGuid,
        ListDate = x.ListDate,
        ListingAge = Logic.App.GetListingAge(x.BirthDate ?? DateTime.Now),
        Image1 = x.Image1
      })
      .ToList();  //Materialize the local query into a real list.
    

    I highly recommend you always .ToList() at the end of these calls. Other wise multiple calls to this method will return literally different list of ResultsViewModel.

    What can happen if you return an IQueryable as an IEnumerable.