首页 > 解决方案 > Entity Framework Core 2.2 使用标量 DBFunction 获取外键列表上的属性

问题描述

我有一个带有外键链接列表的模型,即

[Table("a"]
public class A {
    [Key]
    [Column("a_id")]
    public int Id { get; set; }

    public List<B> Bs { get; set; } = new List<B>();
}

[Table("b"]
public class B {
    [Key]
    [Column("b_id")]
    public int Id { get; set; }
    [NotMapped]
    public string MyFunctionValue { get; set; }

    [ForeignKey("a_id")]
    public A A { get; set; }
}

然后我定义了一个函数,它链接到一个标量 sql 函数,像这样......

public static class MySqlFunctions {
    [DbFunction("MyFunction", "dbo")]
    public static string MyFunction(int bId) {
        throw new NotImplementedException();
    }
}

并像这样在我的上下文中注册...

modelBuilder.HasDbFunction(() => MySqlFunctions.MyFunction(default));

我希望能够在我的存储库类中做的是在一个 List 中获取链接 B 记录的 A 记录,当针对 B 的 id 运行时,它们的 MyFunctionValue 值设置为函数的返回值。类似.. .

myContext.A
    .Include(a => a.Bs.Select(b => new B {
        Id = b.Id,
        MyFunctionValue = MySqlFunctions.MyFunction(b.Id)
    });

但是,到目前为止,我尝试过的所有选项都得到了 InvalidOperationException 或 NotImplementedException 我猜是因为它无法正确地将其转换为 SQL?

有什么方法可以编写这样的查询,或者 EF 生成 SQL 是否太复杂?我知道我可以使用 .FromSql 但如果可能的话我宁愿避免它,因为它有点乱。

编辑:

所以我设法让它与下面的代码一起工作,但它显然有点混乱,如果有人有更好的解决方案,我将不胜感激。

myContext.A
    .Include(a => a.Bs)
    .Select(a => new {
        A = a,
        MyFunctionValues = a.Bs.Select(b => MySqlFunctions.MyFunction(b.Id))
    })
    .AsEnumerable()
    .Select(aWithMfvs => {
        for (int i = 0; i < aWithMfvs.MyFunctionValues.Count(); i++) {
            aWithMfvs.A.Bs[i].MyFunctionValue = aWithMfvs.MyFunctionValues[i];
        }

        return aWithMfvs.A;
    })
    .AsQueryable();

标签: c#.net-coreentity-framework-coreuser-defined-functions

解决方案


使用 db 函数需要考虑以下几点:

  • 当您将 DbFunction 声明为静态方法时,您不必将其注册到 modelBuilder
  • 仅当您使用 Fluent API 时才需要注册(恕我直言,我还是建议您这样做,以使您的实体没有任何依赖关系)
  • 返回值、方法名称以及方法参数的计数、类型和顺序必须与您在用户定义函数 (UDF) 中的代码匹配
    • 您将方法参数命名为bId. 它在您的 UDF 中是否完全一样,或者与表中的一样b_id

推荐阅读