Entity Framework Core 2.2 использует скалярную функцию DBFunction для получения свойства в списке внешних ключей - PullRequest
3 голосов
/ 24 сентября 2019

У меня есть модель со связанным списком внешних ключей, т. Е.

[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));

То, что я хочу иметь в своем классе репозитория, - это захватить записи A со связанными записями B в списке с их MyFunctionValueзначение устанавливается равным возвращаемому значению функции при запуске с идентификатором B. Что-то вроде ...

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();

1 Ответ

1 голос
/ 24 сентября 2019

Есть несколько вещей, которые вы должны рассмотреть с функциями db:

  • Когда вы объявляете DbFunction как статический метод, вам не нужно регистрировать его в modelBuilder
  • Регистрациятребуется только в том случае, если вы используете Fluent API (который я рекомендую в любом случае ИМХО, чтобы у вас не было каких-либо зависимостей)
  • Возвращаемое значение, имя метода и число, тип и порядок методапараметры должны соответствовать вашему коду в пользовательской функции (UDF)
    • Вы назвали параметр метода bId.Это точно так же в вашем UDF или скорее как в таблице как b_id?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...