简体   繁体   English

使用扩展方法从Linq到列表

[英]From Linq To List Using Extension Method

I have this code that runs fine: 我有运行良好的代码:

// my controller //我的控制器

public HttpResponseMessage GetUserFavorites(string id)
{

    var response = Request.CreateResponse();

    response.Content = new StringContent(JsonConvert.SerializeObject(jobRepository.GetUserFavorites(id)));
    response.StatusCode = HttpStatusCode.OK;

    return response;

}

// my jobRepository //我的jobRepository

     public IQueryable<ProfileInfo> GetUserFavorites(string iUserId)
        {


            var profiles = from favoriate in db.TB_Res_Favorites
                           join profile in db.TB_Res_Profile on favoriate.ProfileID equals profile.ProfileID
                           where favoriate.UserId == iUserId

                           select new ProfileInfo()
                           {
                               ProfileID = profile.ProfileID,
                               FullName = profile.FullName,
                               Headline = profile.Headline,
                               Location = profile.Location,
                               Industry = profile.Industry,
                               ImageUrl = profile.ImageUrl,
                               EducationInstitute = profile.EducationInstitute,
                               Degree = profile.Degree
                           };


            return profiles;


        }

The issue is, that the mapping to ProfileInfo will return in many places in my code. 问题是,到ProfileInfo的映射将在我的代码的许多地方返回。 I obviously want to avoid that. 我显然想避免这种情况。 I thought of using extension method, that will map from EF to my class like this: 我想到使用扩展方法,它将像这样从EF映射到我的班级:

// my extension: //我的扩展名:

 public static class ModelExtensions
    {

        public static ProfileInfo ToProfileInfo(this TB_Res_Profile dbProfile)
        {
            return new ProfileInfo
            {

                 ProfileID= dbProfile.ProfileID,
                 FullName = dbProfile.FullName, 
                 Headline = dbProfile.Headline,
                 Location = dbProfile.Location,
                 Industry = dbProfile.Industry,
                 ImageUrl = dbProfile.ImageUrl,
                 EducationInstitute = dbProfile.EducationInstitute,
                 Degree = dbProfile.Degree
            };
        }




    }

and use it like this (controler is not changed): 并像这样使用它(控制器不变):

public IQueryable<ProfileInfo> GetUserFavorites(string iUserId)
{


    var profiles = from favoriate in db.TB_Res_Favorites
                   join profile in db.TB_Res_Profile on   favoriate.ProfileID equals profile.ProfileID
                   where favoriate.UserId == iUserId
                   select profile.ToProfileInfo();


    return profiles;


}

It is compiled OK, but I got this error in run time: 它已编译正常,但在运行时出现此错误:

An exception of type 'System.NotSupportedException' occurred in Newtonsoft.Json.dll but was not handled in user code Newtonsoft.Json.dll发生类型'System.NotSupportedException'的异常,但未在用户代码中处理

Additional information: LINQ to Entities does not recognize the method 'myApp.Models.InfoClass.ProfileInfo ToProfileInfo(myApp.Models.TB_Res_Profile)' method, and this method cannot be translated into a store expression. 附加信息: LINQ to Entities无法识别方法'myApp.Models.InfoClass.ProfileInfo ToProfileInfo(myApp.Models.TB_Res_Profile)'方法,并且该方法无法转换为商店表达式。

I know there are auto mappers that I can use. 我知道我可以使用自动映射器。 but it really interest me to make this work, and understand what is wrong here. 但是让我真正感兴趣的是完成这项工作,并了解这里有什么问题。

You can make it work using extension method if you first force a call to a database using for example ToList() and then use a mapper: 如果首先使用例如ToList()强制调用数据库,然后使用映射器,则可以使用扩展方法使其工作:

var profiles = (from favoriate in db.TB_Res_Favorites
               join profile in db.TB_Res_Profile on   favoriate.ProfileID equals profile.ProfileID
               where favoriate.UserId == iUserId
               select profile).ToList()
               .Select(p => p.ToProfileInfo());
return profiles;

The reason why you need to make a call to a database first, is because Entity Framework is making a translation of your LINQ code to SQL code, and when it finds custom Extension method it obviously cannot make a translation. 之所以需要首先调用数据库,是因为Entity Framework正在将LINQ代码转换为SQL代码,并且当它找到自定义的Extension方法时,显然不能进行转换。

When you force a request to database using ToList() you make a request to extension method in C# code, which is obviously valid thing to do. 当您使用ToList()强制对数据库的请求时,您会使用C#代码向扩展方法发出请求,这显然是正确的做法。

You should pass the whole IQueryable and return another IQueryable . 您应该传递整个IQueryable并返回另一个IQueryable Something like this: 像这样:

public static IQueryable<ProfileInfo> ToProfileInfo(this IQueryable<TB_Res_Profile> query)
{
  return query.Select(p => new ProfileInfo()
  {
    ProfileID= p.ProfileID,
    FullName = p.FullName, 
    Headline = p.Headline,
    Location = p.Location,
    Industry = p.Industry,
    ImageUrl = p.ImageUrl,
    EducationInstitute = p.EducationInstitute,
    Degree = p.Degree
  });
}

Now you only have Expression trees, which EF will be pleased to work with: 现在,您只有表达式树,EF将很高兴与它们一起使用:

var profiles = (from favoriate in db.TB_Res_Favorites
                join profile in db.TB_Res_Profile
                on favoriate.ProfileID equals profile.ProfileID
                where favoriate.UserId == iUserId
                select profile)
                .ToProfileInfo();

You could use the navigation properties , if they're properly set in place, and do something like this: 如果正确设置了导航属性,则可以使用它们,然后执行以下操作:

from p in db.TB_Res_Profile 
where p.TB_Res_Favorite.UserId == iUserId select p;

This way you'll also avoid all that mapping. 这样,您还可以避免所有映射。 Mind using the correct name for the navigation property. 请注意使用导航属性的正确名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM