LINQ to Entities无法识别该方法。 Guid造成麻烦?

时间:2013-07-26 13:59:15

标签: asp.net-mvc linq asp.net-mvc-4

在我的模型类OwnedModule中,我将OwnerID作为Guid。

还有另一个名为BusinessUnit的模型类,它包含来自OwnedModule及其OwnerName的相同Guid值。

我想显示OwnedModule的详细信息,其中包含有关硬件的所有详细信息但是拥有者为Guid值而不是名称,为此我创建了一个视图模型

public class OwnedModuleViewModel
    {
        public long Id { get; set; }
        public string ModuleId { get; set; }
        public string TypeName { get; set; }
        public string KindName { get; set; }
        public string Owner { get; set; }
        public DateTime OwnershipStart { get; set; }
    }
    public class IndexOwnedModule
    {
        public List<OwnedModuleViewModel> OwnedModules { get; set; }
    }

在我的存储库中显示所有这些细节我有以下功能

    public IndexOwnedModule GetAllOwnedModules()
    {

        var modulesList = new IndexOwnedModule();

        var modules = (_dbSis.OwnedModules.OrderBy(module => module.Id).Select(module => new OwnedModuleViewModel
        {
            Id = module.Id,
            ModuleId = module.ModuleId,
            TypeName = module.ModuleType.TypeName,
            Owner = GetModuleOwner(module.ModuleOwnerId),//error here
            OwnershipStart = module.Start
        }));

        modulesList.OwnedModules = modules.ToList();
        return modulesList;

    }

    public string GetModuleOwner(Guid id)
    {
        var ownedModule =_dbSis.Set<BusinessUnit>().FirstOrDefault(t => t.Id == id);
        if (ownedModule != null) return ownedModule.Name;
        return null;
    }

在用户视图中将guid值显示为所有者是不方便的,因此我想获取我有GetModuleOwnerName的名称。

但似乎我将所有者的名称设置为我的viewmodel视图的方式是错误的,当我运行应用程序时,我收到以下错误。

LINQ to Entities无法识别方法'System.String GetModuleOwner(System.Guid)'方法,并且此方法无法转换为商店表达式。

当我评论我设置了所有者值的行(所有者= GetModuleOwner(module.ModuleOwnerId))时,一切正常。

3 个答案:

答案 0 :(得分:3)

当Entity Framework构建您的查询时,它依赖于对传递的表达式树的检查。遇到方法调用时,它会尝试使用(see this for the canonical methods)将其映射到等效的SQL方法。由于实体框架不了解OwnedModuleViewModel.GetModuleOwner,因此无法生成适当的SQL查询。在这种情况下,简单的方法是在查询中嵌入您的方法而不是调用方法:

_dbSis.OwnedModules
      .OrderBy(module => module.Id)
      .Select(module => new OwnedModuleViewModel 
          {
              Id = module.Id,
              ModuleId = module.ModuleId,
              TypeName = module.ModuleType.TypeName,
              Owner = _dbSis.Set<BusinessUnit>()
                            .Where(t => t.Id == module.ModuleOwnerId)
                            .Select(t => t.Name).FirstOrDefault(),
              OwnershipStart = module.Start
          });

当然,假设_dbSis.Set<BusinessUnit>()是同一DbSet<T>的{​​{1}}部分,否则会出现同样的问题。

答案 1 :(得分:1)

在Linq-To-Entities中,针对上下文的Linq语句被转换为SQL语句。将GetModuleOwner()方法转换为SQL显然是不可能的。您需要首先获取ModuleOwnerId,然后在另一个步骤中,在每个ModuleOwnerId上调用GetModuleOwner()。

或者您可以重新构建查询以使用联接:

var modules = from m in _dbSis.OwnedModules
              join b in _dbSis.BusinessUnit on m.ModuleOwnerId equals b.Id
              order by m.Id
              select new OwnedModuleViewModel {
                                      Id = m.Id,
                                      ModuleId = m.ModuleId,
                                      TypeName = m.ModuleType.TypeName,
                                      Owner = b.Name,
                                      OwnershipStart = m.Start};

modulesList.OwnedModules = modules.ToList();

注意:我没有对此进行测试,因此可能会出现一些轻微的语法错误。

答案 2 :(得分:0)

这可能是另一种选择

var ownedModules = _dbSis.OwnedModules.OrderBy(module => module.Id).Select(module => new
            {
                Id = module.Id,
                ModuleId = module.ModuleId,
                TypeName = module.ModuleType.TypeName,
                ModuleOwnerId = module.ModuleOwnerId,
                OwnershipStart = module.Start
            }).ToList().Select(m => new OwnedModuleViewModel
            {
                Id = m.Id,
                ModuleId = m.ModuleId,
                TypeName = m.TypeName,
                Owner = GetModuleOwner(m.ModuleOwnerId),
                OwnershipStart = m.OwnershipStart
            });
            ownedModulesList.OwnedModules = ownedModules.ToList();
            return ownedModulesList;