[c#] EF Code First의 계산 된 열

데이터베이스에서 (행 합계)-(행 합계 b)로 계산 된 데이터베이스에 하나의 열이 있어야합니다. 코드 우선 모델을 사용하여 데이터베이스를 만들고 있습니다.

내가 의미하는 바는 다음과 같습니다.

public class Income {
      [Key]
      public int UserID { get; set; }
      public double inSum { get; set; }
}

public class Outcome {
      [Key]
      public int UserID { get; set; }
      public double outSum { get; set; }
}

public class FirstTable {
      [Key]
      public int UserID { get; set; }
      public double Sum { get; set; }
      // This needs to be calculated by DB as 
      // ( Select sum(inSum) FROM Income WHERE UserID = this.UserID) 
      // - (Select sum(outSum) FROM Outcome WHERE UserID = this.UserID)
}

EF CodeFirst에서이를 어떻게 달성 할 수 있습니까?



답변

데이터베이스 테이블에 계산 된 열 을 만들 수 있습니다 . EF 모델에서는 속성을 사용하여 해당 속성에 주석을 추가하기 만하면됩니다 DatabaseGenerated.

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public double Summ { get; private set; }

또는 유창한 매핑 :

modelBuilder.Entity<Income>().Property(t => t.Summ)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)

Matija Grcic이 제안 하고 주석에서 제안했듯이 속성을 만드는 것이 좋습니다 private set. 왜냐하면 응용 프로그램 코드에서 설정하고 싶지 않기 때문입니다. Entity Framework에는 개인 setter에 문제가 없습니다.

참고 : EF .NET Core의 경우 HasDatabaseGeneratedOption이 없기 때문에 ValueGeneratedOnAddOrUpdate 를 사용해야 합니다. 예 :

modelBuilder.Entity<Income>().Property(t => t.Summ)
    .ValueGeneratedOnAddOrUpdate()


답변

public string ChargePointText { get; set; }

public class FirstTable
{
    [Key]
    public int UserID { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public string Summ
    {
        get { return /* do your sum here */ }
        private set { /* needed for EF */ }
    }
}

참조 :


답변

2019 년부터 EF 코어를 사용하면 유창한 API를 사용하여 깔끔한 방식으로 열을 계산할 수 있습니다.

DisplayName정의하려는 계산 된 열 이라고 가정하고 평소와 같이 속성을 정의해야하며, 할당을 방지하기 위해 개인 속성 접근자를 사용하여 가능할 수 있습니다.

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    // this will be computed
    public string DisplayName { get; private set; }
}

그런 다음 모델 작성기에서 열 정의로 주소를 지정합니다.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>()
        .Property(p => p.DisplayName)
        // here is the computed query definition
        .HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
}

자세한 내용은 MSDN을 참조하십시오 .


답변

EF6에서는 다음과 같이 계산 된 속성을 무시하도록 매핑 설정을 구성 할 수 있습니다.

모델의 get 속성에 대한 계산을 정의합니다.

public class Person
{
    // ...
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName => $"{FirstName} {LastName}";
}

그런 다음 모델 구성에서 무시하도록 설정하십시오.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    //...
    modelBuilder.Entity<Person>().Ignore(x => x.FullName)
}


답변

한 가지 방법은 LINQ를 사용하는 것입니다.

var userID = 1; // your ID
var income = dataContext.Income.First(i => i.UserID == userID);
var outcome = dataContext.Outcome.First(o => o.UserID == userID);
var summ = income.inSumm - outcome.outSumm;

POCO 객체 내에서 할 수는 public class FirstTable있지만 좋은 디자인이 아니라고 생각 하기 때문에 권장 하지 않습니다.

또 다른 방법은 SQL보기를 사용하는 것입니다. Entity Framework를 사용하여 테이블과 같은보기를 읽을 수 있습니다. 그리고 뷰 코드 내에서 계산이나 원하는 것을 할 수 있습니다. 다음과 같은보기를 만드십시오.

-- not tested
SELECT FirstTable.UserID, Income.inCome - Outcome.outCome
  FROM FirstTable INNER JOIN Income
           ON FirstTable.UserID = Income.UserID
       INNER JOIN Outcome
           ON FirstTable.UserID = Outcome.UserID


답변

뷰 모델을 사용하여 이에 대해 설명하겠습니다. 예를 들어 FirstTable 클래스를 db 엔터티로 사용하는 것보다 FirstTable이라는 뷰 모델 클래스를 갖고 계산 된 합계를 포함하는이 클래스를 반환하는 데 사용되는 함수를 갖는 것이 더 낫지 않을까요? 예를 들어 클래스는 다음과 같습니다.

public class FirstTable {
  public int UserID { get; set; }
  public double Sum { get; set; }
 }

그런 다음 계산 된 합계를 반환하는 호출하는 함수가 있습니다.

public FirsTable GetNetSumByUserID(int UserId)
{
  double income = dbcontext.Income.Where(g => g.UserID == UserId).Select(f => f.inSum);
  double expenses = dbcontext.Outcome.Where(g => g.UserID == UserId).Select(f => f.outSum);
  double sum = (income - expense);
  FirstTable _FirsTable = new FirstTable{ UserID = UserId, Sum = sum};
  return _FirstTable;
}

기본적으로 SQL 뷰와 동일하고 @Linus가 언급했듯이 데이터베이스에 계산 된 값을 유지하는 것이 좋은 생각이 아니라고 생각합니다. 약간의 생각.


답변

문자열 열 “Slug”가있는 EF Code First 모델을 다른 문자열 열 “Name”에서 파생 시키려고 할 때이 질문을 우연히 발견했습니다. 제가 취한 접근 방식은 약간 달랐지만 잘 진행되었으므로 여기서 공유하겠습니다.

private string _name;

public string Name
{
    get { return _name; }
    set
    {
        _slug = value.ToUrlSlug(); // the magic happens here
        _name = value; // but don't forget to set your name too!
    }
}

public string Slug { get; private set; }

이 접근 방식의 좋은 점은 슬러그 세터를 노출하지 않고 자동 슬러그 생성을 얻는다는 것입니다. .ToUrlSlug () 메서드는이 게시물의 중요한 부분이 아닙니다. 필요한 작업을 수행하기 위해 그 자리에서 무엇이든 사용할 수 있습니다. 건배!