URI 中指定的查询无效 + 投影 + LINQ Select

The query specified in the URI is not valid + Projection + LINQ Select

如果这是一个重复的问题,我深表歉意。基本上我想要实现的是让我的投影是一个单独的 method/class,我可以像这样重用它(请记住我是 LINQ 的初学者)。

public static Expression<Func<MyObject, object>> getProjection()
    {
        return r => new
        {
            Name = r.Name,
            Address = r.Address,
            City = r.City,
            PostalCode = r.PostalCode,
            Province = r.Province,
            Country = r.Country,
            Phone = r.Phone,
            Website = r.Website
        };
    }

但是,当我这样调用Projection时。

var filteredList = db.MyObject.Select(Projections.getProjection()).AsQueryable();
return Ok(filteredList);

然后我得到错误

The query specified in the URI is not valid. Could not find a property named 'Name' on type 'System.Object'.

如果我仅通过复制和粘贴将 Projection 辅助方法替换为实际的 Projection,那么它就可以工作。我只是想通过创建辅助方法 "getProjection" 来避免为其他 Select 方法再次重写相同的投影。首先,如果您可以验证这是否是调用 Projection 的正确方法。其次,我怎样才能摆脱那个 OData 错误。

谢谢

那么,如果您尝试使用简单的方法而不是表达式呢?

例如:

public static object GetProjection(MyObject o){
    return new{
            Name = o.Name,
            Address = o.Address,
            City = o.City,
            PostalCode = o.PostalCode,
            Province = o.Province,
            Country = o.Country,
            Phone = o.Phone,
            Website = o.Website
    };
}

然后在你的控制器中:

var filteredList = db.MyObject.Select(GetProjection).AsQueryable();
return Ok(filteredList);

LINQ to Entities 需要强类型。它们可以是通用的,并且可以是匿名的。你的问题是你的函数 return 是一个弱类型 Expression>。

使用强类型解决,或者不使用投影方式。

A:强型。这实际上非常整洁,可以被认为是 懒惰 尝试在这里使用匿名类型。

public class MyRecord { /* fields here */ }
public static Expression<Func<MyObject, MyRecord>> getProjection()
{
    return r => new MyRecord
    {
        Name = r.Name,
        Address = r.Address,
        City = r.City,
        PostalCode = r.PostalCode,
        Province = r.Province,
        Country = r.Country,
        Phone = r.Phone,
        Website = r.Website
    };
}

/* of type IQueryable<MyRecord> */
var filteredList = db.MyObject.Select(getProjection());

B:去除投影方式:

/* of type IQueryable<Anonymous> - this is why 'var' exists */
var filteredList = db.MyObject.Select(r => new
{
    Name = r.Name,
    Address = r.Address,
    City = r.City,
    PostalCode = r.PostalCode,
    Province = r.Province,
    Country = r.Country,
    Phone = r.Phone,
    Website = r.Website
});

请注意,如果您打算将此 return 用于另一种方法,您仍然需要强(非匿名)类型。通过方法传递匿名类型的唯一方法是通过泛型。例如:

function T Do<T>(func<T> something) { return something(); }
var anon = Do(() => { a = 1, b = 2 });

C:如果您经常进行此投影并且您不想创建投影 类 那么问问自己 'why not?'。如果您想避免经常编写此项目代码并且乐于创建投影 类,那么请考虑使用诸如 AutoMapper 之类的工具。现在使用很普遍。