c# - 使用 Linq 表达式计算的属性

标签 c# linq entity-framework-5

我正在使用 LINQ to Entities (EF5) 从现有数据库中获取和筛选产品列表。产品的价格可能会或可能会 没有折扣(统一费率或百分比)。我希望在服务器端进行计算,以便我可以轻松过滤、排序和 检索折扣价格,而无需编写大量重复的 Linq,并在顶部重新计算一些客户端代码。

我知道 Linq 无法神奇地将客户端函数转换为 SQL,但据我所知,我可以编写一个表达式 可以翻译成 SQL。看来我应该能够编写一个表达式并将该值存储为“列”。

我见过一些看起来可以实现我想要的效果的示例:

http://blog.cincura.net/230786-using-custom-properties-as-parameters-in-queries-in-ef/

Include derived property into a linq to entity query

问题是,我无法让表达式/属性在基本级别上工作。暂时忘记折扣计算......

下面,我有一个简单的表达式,如果产品 id 大于 3,则计算结果为“true”。我的属性中有一个属性 返回表达式结果的产品模型。当我尝试获取该属性时,我收到 NotSupportedException: “LINQ to Entities 不支持指定的类型成员“test”。仅支持初始值设定项、实体成员和实体导航 支持属性。”

public partial class ProductList
{
    protected void Page_Load(object sender, EventArgs e)
    {           
        using (var db = new eTailerContext())
        {           
            var products = db.products
                       .Select(p => new
                       {
                           id = p.id,
                           name = p.name,
                           mytest = p.test
                       });
        }
    }
}

public class Product
{
    public id { get; set; }
    public name { get; set; }

    public bool test
    {
        get { return testExpression.Compile()(this); }
    }

    public static Expression<Func<Product, bool>> testExpression
    {
        get { return t => t.id > 3; }
    }
}

或者,我已经尝试过

mytest = Product.testExpression.Compile()(p)

但这会引发不同的 NotSupported 异常:“LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”。” 难道真的没有办法做到这一点吗?这似乎是一个很常见的需求。

这是配置代码:

public class ProductMap : EntityTypeConfiguration<Product>
{
    public ProductMap()
    {
        this.HasKey(t => t.id);
        this.ToTable("Products");
        this.Property(t => t.id).HasColumnName("ProductID");
        this.Property(t => t.name).HasColumnName("ProductName").HasMaxLength(255);

        this.Ignore(t => t.test);
    }
}

public class MyDbContext : DbContext
{
    public DbSet<Product> products { get; set; }

    public MyDbContext() : base("Name=SiteSqlServer")
    { }

    static MyDbContext()
    {
        Database.SetInitializer<MyDbContext>(null);
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    { modelBuilder.Configurations.Add(new ProductMap()); }
}

最佳答案

您需要将整个选择包装为表达式。

public class Product
{
    public int id { get; set; }
    public string name { get; set; }

    public bool test
    {
        get { return id > 3;}
    }

    public static Expression<Func<Product, dynamic>> TestExpression = 
                    p => new
                       {
                           id = p.id,
                           name = p.name,
                           mytest = p.id > 3
                       };
}

然后就可以使用

var products = db.products
                   .Select(Product.TestExpression);

这将产生类似的 SQL 语句

SELECT 
    [Extent1].[ProductID] AS [ProductID], 
    [Extent1].[ProductName] AS [ProductName], 
    CASE WHEN ([Extent1].[ProductID] > 3) THEN cast(1 as bit) WHEN ( NOT ([Extent1].[ProductID] > 3)) THEN cast(0 as bit) END AS [C1]
    FROM [dbo].[Products] AS [Extent1]

注意:您可能应该使用真实的类而不是动态的

关于c# - 使用 Linq 表达式计算的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23413296/

相关文章:

c# - MigraDoc - 从十六进制设置单元格颜色

c# - 对排序列表进行分组而不影响 linq 中的排序

c# - ParallelQuerys Count 算什么?

c# - 当 MVC 使用 SQL 2014 介入 EF6 调用时,VS 2013 崩溃

asp.net-mvc-4 - 使用 Entity Framework 5 对非英语语言的表名进行复数化

c# - 初始化内联列表

c# - 从电子表格中读取行数据

c# - 如何使用 SQL 填充 Crystal Reports

c# - 匹配客户在前端选择的搜索属性

Linqpad 性能与 Sql Management Studio