web-dev-qa-db-ja.com

EF Code Firstの計算列

データベースによって(行の合計)-(rowsbの合計)として計算されるデータベースの1つの列が必要です。データベースを作成するためにコードファーストモデルを使用しています。

ここに私が意味するものがあります:

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でこれを達成するにはどうすればよいですか?

68
CodeDemen

データベーステーブルに 計算列 を作成できます。 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にはプライベートセッターに関する問題はありません。

119
Gert Arnold
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 */ }
    }
}

参照:

28
Matija Grcic

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 [〜#〜] をご覧ください。

3
Pier

1つの方法は、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
2
Linus Caldwell

これについては、ビューモデルを使用するだけです。たとえば、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が言及したように、計算された値をデータベースに保持することは良い考えではないと思います。いくつかの考え。

1
craigvl