【问题标题】:Why when I pass a Lambda expressin Func thats give me an error为什么当我传递一个 Lambda 表达式 Func 那给我一个错误
【发布时间】:2010-11-14 04:58:01
【问题描述】:

当我调用一个返回 A Func 的通用方法并传入 Where 的参数时,这是行不通的。 (System.InvalidOperationException:内部 .NET Framework 数据提供程序错误 1025。) 错误是当我想获取角色信息时。
对于角色,我需要执行 Where 子句表达式 EX:(p => p.LangID == 1)

此代码不起作用

在仓库中

public Func<T, bool> GetLmbLang<T>() where T:class,IBaseGenericTxt
    {
        int lang = -1;
        lang = Convert.ToInt32(HttpContext.Current.Session["Language"]);
        return (p => p.LangID == lang);
    }

在控制器中

                var ViewModel = _db.Contacts.Where(a=> a.IsActive == true).Select(a => new ContactListViewModel { 
                    ContactID = a.ContactID,
                    ContactName = a.ContactName,
                    Role = a.ContactType.ContactTypeTexts.Where(repGeneric.GetLmbLang<ContactTypeText>()).Select(af => af.Txt).FirstOrDefault(),
                    CompanyType = a.Supplier.SupplierName,
                    Addr = a.Address ,
                    Email = a.ContactEmail,
                    Phone = a.ContactPhone
                }).ToList();
                for (int i = 0; i < ViewModel.Count(); i++)
                {
                    Response.Write(ViewModel.ElementAt(i).ContactID + "<br />");
                }

此代码有效

 int lang = -1;
            lang = Convert.ToInt32(Session["Language"]);
            var ViewModel = _db.Contacts.Where(a=> a.IsActive == true).Select(a => new ContactListViewModel { 
                ContactID = a.ContactID,
                ContactName = a.ContactName,
                Role = a.ContactType.ContactTypeTexts.Where(p => p.LangID == lang).Select(af => af.Txt).FirstOrDefault(),
                CompanyType = a.Supplier.SupplierName,
                Addr = a.Address ,
                Email = a.ContactEmail,
                Phone = a.ContactPhone
            }).ToList();
            for (int i = 0; i < ViewModel.Count(); i++)
            {
                Response.Write(ViewModel.ElementAt(i).ContactID + "<br />");
            }

我的 ContactListViewModel

public class ContactListViewModel
    {
        public int ContactID { get; set; }
        public string ContactName { get; set; }
        public string Role { get; set; }
        public string Company { get; set; }
        public string CompanyType { get; set; }
        public Address Addr { get; set; }
        public string Email { get; set; }
        public string Phone { get; set; }
    }

我的列表视图

 ..... Inherits="System.Web.Mvc.ViewPage<List<mvcinfosite.ViewModels.ContactListViewModel>>" %>
 <table class="genTable">


    <% for (int i = 0;i < Model.Count; i++) { %>
        <tr>
            <td>
                <%: Html.ActionLink(item.ContactName, "Edit", new { id=item.ContactID }) %>
            </td>

            <td>
                <%: item.Role  %>
            </td>

            <td>
                <%: item.Company %>
            </td>

            <td>
                <%: item.CompanyType  %>
            </td>

            <td>
                <%: GlobalHelper.GetAddress(item.Addr) %>
            </td>
            <td>
                <%: item.Email %>
            </td>
            <td>
                <%: item.Phone %>
            </td>
        </tr>

    <% } %>

    </table>

【问题讨论】:

  • 非常混乱的代码。你在做_db.Contacts.ToList()(基本上是抓取所有联系人),然后对他们处于活动状态的联系人进行 another 查询,做AsQueryable() (这是多余的),但我认为主要问题是你的尝试在您的投影中进行内联查询(即 Role 属性)。也许如果您解释您要做什么,我们可以帮助您编写更好的查询。
  • 我想用我所有的活跃联系人填满一个表格。你是对的 AsQueryable()。我做了很多测试,只是忘记在我的帖子中删除它。角色是一个字符串,我需要从我的联系人类型文本中获取此值。我将更新我的原始帖子以添加详细信息

标签: asp.net-mvc-2 entity-framework-4 lambda


【解决方案1】:

正如 naasking 指出的那样,您需要使用 Func 的表达式而不是直接的 Func:

public Expression<Func<T, bool>> GetLmbLang<T>() where T:class,IBaseGenericTxt
{
    int lang = -1;
    lang = Convert.ToInt32(HttpContext.Current.Session["Language"]);
    return (p => p.LangID == lang);
}

编辑

啊,是的,问题是你的函数在编译时实际上并不知道它正在使用什么类:它只知道它是一个类,并且它实现了 IBaseGenericTxt。所以当你说p.LangId 时,这部分表达式是调用 IBaseGenericTxt.LangId,而不是 ContactTypeText.LangId。

您需要构建自己的表达式树才能使其正常工作。像这样的:

var paramExpr = Expression.Parameter(typeof(T), "p");
return Expression.Lambda<Func<T, bool>>(
    Expression.Equal(
        Expression.Property(paramExpr, "LangId"),
        Expression.Constant(lang)),
    paramExpr);

编辑 2

两件事:

  1. 因为 LINQ to Entities 会尝试获取查询表达式中的任何内容并将其转换为 SQL 语句,所以您必须小心不要在查询中间调用方法。您需要先调用 GetLmbLang 方法并将其值存储在一个变量中以在查询中使用。
  2. 正如您在评论中指出的那样,由于 ContactTypeTexts 属性没有实现 IQueryable,这变得特别棘手。据我所知,您有三个选择:

    1. 将整个选择语句创建为表达式树。这非常烦人且容易出错。
    2. 使用 Joe Albari 的LinqKit 来“编译”和“扩展”您的查询。 LinqKit 将遍历表达式树并构建一个新树,其中您的查询表达式将转换为其等效的 Func。
    3. 返回到您的数据上下文,而不是使用 ContactTypeTexts 属性。

就个人而言,我可能会选择最后一个选项,如下所示:

var lambdaLang = repGeneric.GetLmbLang<ContactTypeText>();
var ViewModel = _db.Contacts
    .Where(a=> a.IsActive == true)
    .Select(a => new ContactListViewModel { 
    ContactID = a.ContactID,
    ContactName = a.ContactName,
    Role = _db.ContactTypeTexts
        .Where(ct => ct.ContactType.Contacts.Any(
            c => c.ContactId == a.ContactId)
        .Where(lambdaLang)
        .Select(af => af.Txt).FirstOrDefault(),
    CompanyType = a.Supplier.SupplierName,
    Addr = a.Address ,
    Email = a.ContactEmail,
    Phone = a.ContactPhone
}).ToList();

【讨论】:

  • 好的,我试试看,但这给了我 2 个错误。错误 1 ​​实例参数:无法从 'System.Data.Objects.DataClasses.EntityCollection' 转换为 'System.Linq.IQueryable' C:\inetpub\wwwroot\myproject\ myproject\Controllers\ContactController.cs 35 24 myproject
  • 第二个是:错误2'System.Data.Objects.DataClasses.EntityCollection'不包含'Where'的定义和最好的扩展方法重载'System. Linq.Queryable.Where(System.Linq.IQueryable, System.Linq.Expressions.Expression>)' 有一些无效参数 C:\inetpub\wwwroot\myproject\ myproject\Controllers\ContactController.cs 35 24 myproject
  • @Jean-Francois: voyez le mise-a-jour ci-dessus。
  • 很好,我明白你在说什么,但这不起作用。出现问题是因为我在 contacttypetext 上进行了子查询。如果我直接在实体上应用该功能,例如 . _db.ContactTypeTexts.Where(repGeneric.GetLmbLang()) ,这工作。如果我在像 _db.Contacts.Select(a => new { SingleContactType = a.ContactType.ContactTypeTexts.Where(repGeneric.GetLmbLang())}) 这样的 Select 中做同样的事情,那就失败了.. (MERCI BEAUCOUP POUR TON AIDE @StriplingWarrior)
  • @StriplingWarrior。谢谢你的帮助。很好的解释。在这个问题上支持我付出了很多努力。我真的很感激你在这里所做的一切。请确保,如果我能在某事上帮助您,我会尽力帮助您。
【解决方案2】:

后一个代码有效,因为 C# 编译器将其转换为表达式树,即。 System.Linq.Expression,而您的原始代码被编译为 Func。当前设计的 Linq to SQL 无法处理 Func,只能处理表达式树。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多