使用Expression <func <...>&gt; </func <...>的linq to sql自定义方法

时间:2014-01-04 11:23:28

标签: c# asp.net-mvc-4 linq-to-sql

也许我在这个问题上让自己有些困难。目标是使用一个对象(此处为SearchForm)来分析数据库记录,并在记录与搜索条目匹配时返回。

由于我的网站允许使用高级搜索表单,因此SearchForm对象包含很多属性(5个输入字段,一些下拉列表和许多复选框)。 我正在使用

  • C#NET 4.0(网络主机不高)
  • LINQ到SQL
  • ASP.NET MVC 4

到目前为止,这是我的代码段:

public static IEnumerable<CarDetails> SearchByForm(SearchForm form) {
    // get db instance
    _db = new MyDBDataContext();
    var q = from Cars_car c in _db.Cars_cars
    join Cars_equipment e in _db.Cars_equipments on c.equipmentId equals e.id
    where ValidData.Invoke(c, form)
    select new CarDetails {
         // filling CarDetails data
    };
    return q;
}

ValidData方法是Expression<Func<...>类型。

private static Expression<Func<Cars_car, SearchForm, bool>> ValidData = (c, f) => MatchesSearchData(f, c);

其中MatchesSearchData是验证每条记录的方法

private static bool MatchesSearchData(SearchForm f, Cars_car c) {
    // long check if true or false and returns it
}

the overloaded method has some invalid arguments处有一个错误ValidData.Invoke(c, form)

我让自己变得困难,还是这是完成我的成绩的好方法? 如果是这样,有人可以为我提供上述错误提示的解决方案吗? 如果没有,一些指导用其他方法来解决这个问题?

有一种方法可以使用存储过程执行此操作,是的,但我更喜欢在此层执行此操作。

使用过的来源;

编辑1

用户Erti-Chris Eelmaa的回答使用Compile() - 方法解决了编译器错误。

    where ValidData.Compile().Invoke(c, form)

但是在运行时,它会将我重定向到错误页面。显然,我收到method has no supported translation to sql错误。

在控制器中,

public ActionResult Results(SearchForm form) {
    ViewBag.cars = Cars_car.SearchByForm(form);
    return View("Results");
}

和模板(只是快速测试)

@foreach (var car in ViewBag.cars)** {
<p>results : car.Make !</p>
}

**这里抛出了method Boolean Invoke(MVCproject2.Models.Cars_car, MVCproject2.Models.SearchForm) has no supported translation to sql错误。这很奇怪,因为添加了Expression方法来为LINQ to SQL提供自定义方法。

或者我错了?

2 个答案:

答案 0 :(得分:1)

如果希望方法成为SQL查询的一部分,则需要在SQL Server上创建方法,然后调用它。像这样:

CREATE FUNCTION ReverseCustName(@string varchar(100))
RETURNS varchar(100)
AS
BEGIN
    DECLARE @custName varchar(100)
    -- Implementation left as exercise for users.
    RETURN @custName
END

// and C# part

[Function(Name = "dbo.ReverseCustName", IsComposable = true)]
[return: Parameter(DbType = "VarChar(100)")]
public string ReverseCustName([Parameter(Name = "string",
    DbType = "VarChar(100)")] string @string)
{
    return ((string)(this.ExecuteMethodCall(this,
        ((MethodInfo)(MethodInfo.GetCurrentMethod())),
        @string).ReturnValue));
}

现在可以在“SQL”查询中使用ReverseCustName(字符串)。

来源:http://msdn.microsoft.com/en-us/library/vstudio/bb386973(v=vs.100).aspx

或者,您可以将所有内容下载到C#客户端并在那里执行Where

public static IEnumerable<CarDetails> SearchByForm(SearchForm form) {
    Func<RetailCar_car, SearchForm> compiledLambda = ValidData.Compile();
    // get db instance
    _db = new MyDBDataContext();
    var q = (from Cars_car c in _db.Cars_cars
    join Cars_equipment e in _db.Cars_equipments on c.equipmentId equals e.id)
    .ToList()
    .Where(x => compiledLambda(c, form))
    .Select(x => new CarDetails {});

    return q;
}

让我们直截了当:当您使用DbContext时,您正在使用IQueryable。该类用于生成SQL查询。如果将C#方法与IQueryable结合使用,LINQSQL不知道如何将其转换为SQL查询。

这两个解决方案对应于:在SQL Server中创建新的SQL方法,或者使用ToList()将所有内容下载到C#端,这意味着IQueryable将切换到IEnumerable

答案 1 :(得分:0)

您能否确认以下LINQ是否正确

var q = from Cars_car c in _db.Cars_cars
    join Cars_equipment e in _db.Cars_equipments on c.equipmentId equals e.id 

我无法理解你为什么在别名中使用别名。据我说,这个片段应该像

var q = from c in _db.Cars_cars
        join e in _db.Cars_equipments on c.equipmentId equals e.id 

可能这不是错误的原因,但我想确认我的理解是否正确。