简体   繁体   English

Linq-如何在查询中使用函数

[英]Linq - how can I use a function in a query

I use C# on WP7 (Mango). 我在WP7(芒果)上使用C#。 I try to use a special query because I receive an error: 我尝试使用特殊查询,因为收到错误:

Method 'Int32 orderBirthday(System.DateTime)' has no supported translation to SQL. 方法'Int32 orderBirthday(System.DateTime)'不支持SQL转换。

Yes, I know... Linq can't use my function but I don't know the right way... 是的,我知道... Linq无法使用我的函数,但我不知道正确的方法...

I have a database table with the columns name and birthday . 我有一个数据库表,其中包含namebirthday列。 In my query I will calculate how many days are to the next birthday (from all items) and then I will order with "descending". 在我的查询中,我将计算(从所有项目中)到下一个生日有几天,然后我将按“降序”排序。

static int orderBirthday(DateTime Birthday)
    {
        DateTime today = DateTime.Today;
        DateTime birthday = Birthday;
        DateTime next = new DateTime(today.Year, birthday.Month, birthday.Day);

        if (next < today)
            next = next.AddYears(1);

        int numDays = (next - today).Days;

        // No Conversion
        return numDays;
    }

 public void LoadCollectionsFromDatabase()
    {

        DateTime today = DateTime.Today;

        var toDoItemsInDB = from ToDoItem todo in toDoDB.Items
                            let daysToBirthday = orderBirthday(todo.ItemDate)
                            orderby daysToBirthday ascending
                            select todo;

        // Query the database and load all to-do items.
        AllToDoItems = new ObservableCollection<ToDoItem>(toDoItemsInDB);
.
.
.
}

You either have to pull everything from the database and sort it locally (as Enigmativity) shows, or find a way to express the sort operation in a LINQ statement itself. 您要么必须从数据库中提取所有内容并对其进行本地排序(如Enigmativity所示),要么必须找到一种方法来表达LINQ语句本身中的排序操作。 And since you extracted the sorting behavior into its own function, you probably want to reuse this logic. 并且由于将排序行为提取到了自己的函数中,因此您可能想重用此逻辑。 In that case your best bet is to create a function that filters an IQueryable . 在这种情况下,最好的选择是创建一个过滤IQueryable的函数。

Here is an example of how to do this: 这是如何执行此操作的示例:

public static IOrderedQueryable<Item> OrderByBirthday(
    this IQueryable<Item> items)
{
    return
        from item in items
        let today = DateTime.Today
        let birthday = item.ItemDate
        let next = new DateTime(today.Year, birthday.Month, birthday.Day)
        let next2 = next < today ? next.AddYears(1) : next
        orderby (next - today).Days
        select item;
}

You can use the method as follows: 您可以使用以下方法:

var toDoItemsInDB = OrderByBirthday(toDoDB.Items);

Or you can use it as an extension method: 或者,您可以将其用作扩展方法:

var toDoItemsInDB = toDoDB.Items.OrderByBirthday();

It's easy if you do this: 如果这样做,这很容易:

    var toDoItemsInDB = from ToDoItem todo in toDoDB.Items.ToArray()
                        let daysToBirthday = orderBirthday(todo.ItemDate)
                        orderby daysToBirthday ascending
                        select todo.;

Notice the .ToArray() added to Items . 注意将.ToArray()添加到Items You basically bring the results into memory and them your function can work. 您基本上将结果存储到内存中,并且您的函数可以使用它们。

Two ways: 两种方式:

One: Pull it from Linq2SQL to Linq2Objects using ToEnumerable() , and then use orderBirthday at the C# level. 一:使用ToEnumerable()将它从Linq2SQL拉到ToEnumerable() ,然后在C#级别使用orderBirthday

Advantage is that it's simple to code and maintain, disadvantage is that it can be less efficient (depends on just what you are doing. 优点是它的简单编码和维护,缺点是,它可以是低效率的(取决于你在做什么。

Two: Write an equivalent function in SQL, let's say it was called dbo.orderBirthday . 二:在SQL中编写一个等效的函数,假设它称为dbo.orderBirthday Make your orderBirthday method a non-static method of your datacontext-derived class, and then mark your method as having a SQL function equivalent: 使您的orderBirthday方法成为datacontext派生类的非静态方法,然后将您的方法标记为具有与SQL函数等效的方法:

[Function(Name="dbo.orderBirthday",IsComposable=true)] //IsComposable is true for functions that can be used within queries, false for stored procedures that must be called on their own.
public int OrderBirthday([Parameter(Name="@birthday",DbType="datetime") DateTime birthday)
{
    return Helper.OrderBirthday(birthday); // just to show that we can keep the static version around if we want and call into it. Alternatively we could just move the whole body here.
}

Here the C# code is used in a non-Linq2SQL context, and the SQL code is used in composing a SQL query in a Linq2SQL context. 此处,C#代码用于非Linq2SQL上下文,而SQL代码用于在Linq2SQL上下文中构成SQL查询。

Advantage: Can stay within SQL longer. 优点:可以在SQL中停留更长时间。 Disadvantage: Two versions of the same method can fall out of sync and cause bugs. 缺点:相同方法的两个版本可能会不同步并导致错误。

It's also possible to have the C# code call the SQL code all the time: 也可能总是让C#代码调用SQL代码:

[Function(Name="dbo.orderBirthday",IsComposable=true)]
public int OrderBirthday([Parameter(Name="@birthday",DbType="datetime") DateTime birthday)
{
    return (int)ExecuteMethodCall(this, (MethodInfo)MethodInfo.GetCurrentMethod(), birthday).ReturnValue;
}

Advantage: Keeps one version (the SQL) as the only version, so it can't fall out of synch with the C# version. 优点:将一个版本(SQL)保留为唯一版本,因此它不会与C#版本不同步。 Disadvantage: Calls SQL even when working on objects that have nothing to do with SQL. 缺点:即使在处理与SQL无关的对象时也调用SQL。

如果您不想将所有项目都加载到内存中,并且希望数据库执行计算,则可以编写一个可以执行复杂计算的存储过程,并使用ADO或EF调用该过程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM