创建可在LINQ(EF)中使用的辅助方法

时间:2014-01-30 16:40:49

标签: c# sql-server linq entity-framework

情境:

当列FooTableFoo时,我有一个表varchar(8) NOT NULL,此列中的信息如下:

Foo
-----------
13940-00
13940-01
13940-02
13941-00
13941-01

连字符后面的数字部分(-)总是有两位数。

问题:

我正在使用Ado.net Entity Framework,我创建了一个包含2个静态方法的类来帮助获取数字的第一和第二部分:

public class HelperFoo
{
    public static string Prefix(string value) { /* code here */ }
    public static string Suffix(string value) { /* code here */ }
}

所以现在我可以这样做:

context.FooTable.Where(w => HelperFoo.Prefix(w.Foo) == "13940");

但是,正如您可能已经知道的那样,此命令行会抛出NotSupportedException。这是因为LINQ无法识别HelperFoo.Prefix,因此无法在SQL中转换表达式。

我可以在SQL中编写一个与HelperFoo方法相同的代码块,这样我就可以为我的方法创建SQL。

问题

我可以创建一些东西(类,方法或其他),使LINQ在执行LINQ代码时知道我的方法吗?

EDITED

PS :我需要一些类似于方法或SQL函数的泛型,因为我需要在Select,OrderBy,GroupBy和其他许多场景中获得此前缀和后缀。

6 个答案:

答案 0 :(得分:2)

你可以尝试为FooTable创建自己的IQueryable过滤器,有点像这样:

public static class Filters
{
    public static IQueryable<FooTable> WithPrefix(this IQueryable<FooTable> item, string prefix)
    {
        return item.Where(i => i.Foo.StartsWith(prefix));
        // note that this should be the same code you have in the 
        // Prefix() method inside HelperFoo...
    }
}

您可以这样使用:

context.FooTable.WithPrefix("13940");

更新:遗憾的是,此处的第二个选项不起作用:

另一个选择是让帮助方法不为Predicate<>返回值FooTable

public class HelperFoo
{
    public static Func<FooTable, bool> Prefix(string value)
    {
        return (i) => i.Foo.Substring(0, 5) == value;
    }
    public static Func<FooTable, bool> Suffix(string value) { /* code here */ }
}

并像这样使用它:

context.FooTable.Where(HelperFoo.Prefix("13940"));

警告:我不完全确定第二种方法不会给你带来同样的问题。

答案 1 :(得分:2)

使用芒果的plethera,你说它需要更通用,你需要前缀和后缀可用SelectOrderBy,&amp; GroupBy个关键字,您应该在两个不同的字段中包含前缀和后缀。

Foo Table
----------
Prefix | Suffix
----------------
10245  | 05

通过它,您可以单独查询它们以获得您想要的内容:

var resultSet = Db.Foo.Where(x => x.Suffix == "05").OrderBy(x => x.Prefix);

使用此功能,您可以轻松添加只读属性以获取格式化值:

public [partial] class Foo {
    //Your other code

    public string FormattedValue {
        get { return Prefix + "-" + Suffix; }
    }
}

答案 2 :(得分:1)

您可以使用.StartsWith检查前缀:

string prefix = "13940";
var result = context.FooTable.Where(w => w.Foo.StartsWith(prefix + "-"));

.EndsWith检查后缀:

string suffix = "02";
var result = context.FooTable.Where(w => w.Foo.EndsWith("-" + suffix));

答案 3 :(得分:0)

您可以在Foo类中创建自定义getter:

public class Foo
{
    //your code
    [NotMapped]
    public string Prefix { get { return /*whatever*/; }
}

我认为这应该有用。

答案 4 :(得分:0)

您无法根据自定义函数过滤数据库选择 - 正如您所说,它无法将其转换为SQL。

对于这个特定问题,我建议你使用StartsWith函数,它可以在SQL服务器上运行

context.FooTable.Where(w => w.Foo.StartsWith("13940"));

答案 5 :(得分:0)

使用Microsoft.Linq.Translations

它看起来像这样:

partial class FooTable 
{
    private static readonly CompiledExpression<FooTable,string> prefixExpression
            = DefaultTranslationOf<FooTable>.Property(e => e.Prefix).Is(e => e.Foo.Substring(0, 5));

    public string Prefix
    {
        get { return prefixExpression.Evaluate(this); }
    }
}

并且询问:

context.FooTable.Where(w => w.Prefix == "13940").WithTranslations();

Nuget gallery page

Documentation

编辑:此解决方案适用于Select,GroupBy,OrderBy。