有一种名为Product的实体类型是由实体框架生成的。 我写了这个问题

public IQueryable<Product> GetProducts(int categoryID)
{
    return from p in db.Products
           where p.CategoryID== categoryID
           select new Product { Name = p.Name};
}

下面的代码抛出以下错误:

实体或复杂类型的Shop。产品不能构造在 LINQ到实体查询"

var products = productRepository.GetProducts(1).Tolist();

但是当我使用select p而不是select new Product {Name = p.Name};它工作正常。

如何执行自定义选择节?


当前回答

在许多情况下,并不需要这种转换。考虑一下您需要强类型List的原因,并评估您是否只是需要数据,例如,在web服务中或用于显示数据。这与类型无关。 您只需要知道如何读取它,并检查它是否与您定义的匿名类型中定义的属性相同。这是最优的情况,因为你不需要实体的所有字段,这就是匿名类型存在的原因。

一个简单的方法是这样做:

IEnumerable<object> list = dataContext.Table.Select(e => new { MyRequiredField = e.MyRequiredField}).AsEnumerable();

其他回答

你可以像下面这样添加AsEnumerable到你的集合:

public IQueryable<Product> GetProducts(int categoryID)
{
    return from p in db.Products.AsEnumerable()
           where p.CategoryID== categoryID
           select new Product { Name = p.Name};
}

为了回应另一个被标记为重复的问题(见这里),我根据Soren的答案想出了一个快速而简单的解决方案:

data.Tasks.AddRange(
    data.Task.AsEnumerable().Select(t => new Task{
        creator_id   = t.ID,
        start_date   = t.Incident.DateOpened,
        end_date     = t.Incident.DateCLosed,
        product_code = t.Incident.ProductCode
        // so on...
    })
);
data.SaveChanges();

注意: 这个解决方案只适用于Task类上有一个导航属性(外键)(这里称为“Incident”)。 如果你没有,你可以使用“AsQueryable()”其他发布的解决方案之一。

另一种简单的方法:)

public IQueryable<Product> GetProducts(int categoryID)
{
    var productList = db.Products
        .Where(p => p.CategoryID == categoryID)
        .Select(item => 
            new Product
            {
                Name = item.Name
            })
        .ToList()
        .AsQueryable(); // actually it's not useful after "ToList()" :D

    return productList;
}

只添加AsEnumerable():

public IQueryable<Product> GetProducts(int categoryID)
{
    return from p in db.Products.AsEnumerable()
           where p.CategoryID== categoryID
           select new Product { Name = p.Name};
}

它不会让您映射回Product,因为这是您正在查询的表。你需要一个匿名函数,然后你可以将它添加到一个ViewModel,并将每个ViewModel添加到List<MyViewModel>并返回这些。这是一个轻微的题外话,但我包含了关于处理可为空日期的警告,因为这是一个难以处理的问题,以防您有任何问题。我是这样处理的。

希望你有一个ProductViewModel:

public class ProductViewModel
{
    [Key]
    public string ID { get; set; }
    public string Name { get; set; }
}

我有依赖注入/存储库框架,我调用一个函数来获取我的数据。以你的帖子为例,在你的Controller函数调用中,它看起来是这样的:

int categoryID = 1;
var prods = repository.GetProducts(categoryID);

在存储库类中:

public IEnumerable<ProductViewModel> GetProducts(int categoryID)
{
   List<ProductViewModel> lstPVM = new List<ProductViewModel>();

   var anonymousObjResult = from p in db.Products
                            where p.CategoryID == categoryID 
                            select new
                            {
                                CatID = p.CategoryID,
                                Name = p.Name
                            };

        // NOTE: If you have any dates that are nullable and null, you'll need to
        // take care of that:  ClosedDate = (DateTime?)p.ClosedDate ?? DateTime.Now

        // If you want a particular date, you have to define a DateTime variable,
        // assign your value to it, then replace DateTime.Now with that variable. You
        // cannot call a DateTime.Parse there, unfortunately. 
        // Using 
        //    new Date("1","1","1800"); 
        // works, though. (I add a particular date so I can edit it out later.)

        // I do this foreach below so I can return a List<ProductViewModel>. 
        // You could do: return anonymousObjResult.ToList(); here
        // but it's not as clean and is an anonymous type instead of defined
        // by a ViewModel where you can control the individual field types

        foreach (var a in anonymousObjResult)
        {                
            ProductViewModel pvm = new ProductViewModel();
            pvm.ID = a.CatID;  
            pvm.Name = a.Name;
            lstPVM.Add(rvm);
        }

        // Obviously you will just have ONE item there, but I built it 
        // like this so you could bring back the whole table, if you wanted
        // to remove your Where clause, above.

        return lstPVM;
    }

回到控制器,你需要:

 List<ProductViewModel> lstProd = new List<ProductViewModel>();

 if (prods != null) 
 {
    // For setting the dates back to nulls, I'm looking for this value:
    // DateTime stdDate = DateTime.Parse("01/01/1800");

    foreach (var a in prods)
    {
        ProductViewModel o_prod = new ReportViewModel();
        o_prod.ID = a.ID;
        o_prod.Name = a.Name;
       // o_prod.ClosedDate = a.ClosedDate == stdDate ? null : a.ClosedDate;
        lstProd.Add(o_prod);
    }
}
return View(lstProd);  // use this in your View as:   @model IEnumerable<ProductViewModel>