UDF(User Defined Function)

Eunho Bae·2022년 7월 1일
0

정의

우리가 직접 만든 SQL을 호출하게 하는 기능이다. 연산을 DB쪽에서 하도록 떠넘기고 싶을 때 사용한다. 또 EF Core 쪽에서 비효율적인 쿼리를 짤 수 있을 때 우리가 직접 정의할 수 있다.

SQL 쿼리를 만든 후 DB에 등록하고 등록한 함수를 호출하도록 하자

스텝

Configuration

static 함수를 만들고 EF Core에 등록

DataModel

 public class ItemReview
    {
        public int ItemReviewId { get; set; }
        public int Score { get; set; }
    }

    [Table("Item")]
    public class Item
    {
    	...
    
        public ICollection<ItemReview> Reviews { get; set; }
    }
    	

Program

  [DbFunction()] // UDF로 인식
        public static double? GetAverageReviewScore(int itemId)
        {
            throw new NotImplementedException("C#에서 사용금지!");
        }

강의에서는 클래스를 따로 만들지 않고, 그냥 Program 클래스 안에 static 함수를 정의하였다. C# 코드에서 호출되면 바로 Exception을 날리도록 정의했고, [DbFunction()]을 삽입하여 UDF로 인식되게 하였다. Fluent API로도 UDF로 인식하게 할 수는 있으나 어노테이션 방식이 더 깔끔하다.

Fluent API 방식

 builder.HasDbFunction(() => Program.GetAverageReviewScore(0)); // 아무값이나 인자로

Database setup

DbCommands

cmd 문자열에 함수 몸체를 다음과 같이 SQL 구문을 정의한다.

// Database Setup
                string cmd = @"CREATE FUNCTION GetAverageReviewScore (@itemId INT) RETURNS FLOAT
                                AS
                                BEGIN
                                
                                DECLARE @result AS FLOAT
                                
                                SELECT @result = AVG(CAST([Score] AS FLOAT))
                                FROM ItemReview AS r
                                WHERE @itemId = r.ItemId

                                RETURN @result

                                END
                                ";

                db.Database.ExecuteSqlRaw(cmd);

사용법

			...
            items[0].Reviews = new List<ItemReview>()
            {
                new ItemReview() { Score = 5 },
                new ItemReview() { Score = 3 },
                new ItemReview() { Score = 1 },
            };
            
            ...
            
        public static void CalcAverage()
        {
            using (AppDbContext db = new AppDbContext())
            {
                foreach (var avg in db.Items.Select(i => Program.GetAverageReviewScore(i.ItemId)))
                {
                    if(avg == null)
                        Console.WriteLine("리뷰 없음");
                    else
                        Console.WriteLine($"Avg : {avg.Value}");
                }
            }

        }
profile
개인 공부 정리

0개의 댓글