2016-09-14 9 views
0

次のようなInitial:Migrationファイルを使用してデータベースに列を作成しようとしています。this guideデータベース作成の計算フィールドの作成CodeFirst/EntityFramework

私はTransactionテーブルとAccountテーブルを持っています。私はAccountプロパティReconciledBalanceを生成しようとしています。 IsReconciledが真で、IsActiveが真である取引のすべての残高の合計を計算する必要があります。

// Example of calculation 
ReconciledBalance = Transactions.Where(t => t.IsActive == true && t.IsReconciled == true).Sum(x => x.Amount) 

これは、計算された列で達成したいことです。私が近づいているのか、あるいは正しい方向に向かっているのか疑問に思っています。どんな助けもありがとう!

// Initial.cs file 
public partial class Initial : DbMigration 
{ 
    public override void Up() 
    { 
     CreateTable(
      "dbo.Accounts", 
     c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      IsActive = c.Boolean(), 
      Name = c.String(), 
      Balance = c.Decimal(nullable: false, precision: 18, scale: 2), 
      //ReconciledBalance = c.Decimal(), 
      HouseholdId = c.Int(), 
     }) 
     .PrimaryKey(t => t.Id) 
     .ForeignKey("dbo.Households", t => t.HouseholdId); 
     Sql("ALTER TABLE dbo.Accounts NOT SURE WHAT TO PUT HERE"); 
    } 

    public override void Down() 
    { 
     //AlterColumn("dbo.Accounts", "ReconciledBalance", c => c.Decimal(nullable: false, precision: 18, scale: 2)); 
     DropTable("dbo.Accounts"); 
    } 
} 

//Account Model 
public class Account 
{ 
    public Account() 
    { 
     this.Transactions = new HashSet<Transaction>(); 
    } 

    public int Id { get; set; } 
    public bool IsActive { get; set; } 
    public string Name { get; set; } 
    [Range(double.MinValue, double.MaxValue)] 
    public decimal Balance { get; set; } 
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
    [Range(double.MinValue, double.MaxValue)] 
    public decimal ReconciledBalance{ get; set; } 
    } 

    //FKs 
    public int HouseholdId { get; set; } 

    //Virtual Properties 
    public virtual Household Household { get; set; }// One to one 
    public virtual ICollection<Transaction> Transactions { get; set; } 
} 

// Account Transaction 
public class Transaction 
{ 
    public Transaction() 
    { 
    } 

    public int Id { get; set; } 
    public bool IsActive { get; set; } 
    [DisplayFormat(DataFormatString = "{0:g}", ApplyFormatInEditMode = true)] 
    public DateTimeOffset Date { get; set; } 
    [StringLength(150, ErrorMessage ="Description cannot exceed 150 characters.")] 
    public string Description { get; set; } 
    [Range(double.MinValue, double.MaxValue)] 
    public decimal Amount { get; set; } 
    public bool IsReconciled { get; set; } 
    public bool IsExpense { get; set; } 
    [Range(double.MinValue, double.MaxValue)] 
    public decimal ReconciledAmount { get; set; } 

    //FKs 
    public int CategoryId { get; set; } 
    public string EnteredById { get; set; } 
    public int AccountId { get; set; } 

    //Virtual Properties 
    public virtual Category Category { get; set; } 
    public virtual ApplicationUser EnteredBy { get; set; } 
    public virtual Account Account { get; set; } 

} 
+0

データベースで計算したい場合は、計算されたフィールドを持つデータベースビューに「Account」エンティティをリンクするか、トランザクションテーブルでトリガを使用する必要があります。 – Colin

+0

私はこれを私のalter tableステートメントで遠くまで得ました。 'Sql(" ALTER TABLE dbo.Accounts ADD ReconciledBalance Decimal SELECT SUM(Amount)FROM [トランザクション] WHERE IsReconciled = 1またはIsActive = 1またはIsVoid = 0 ");' しかし、計算フィールドを追加していません。私はこれをSQLで実行しようとしましたが、フィールドを作成していません。私はOPにリンクしている文書から、私はAS演算子が必要なように見えますが、SQLはそこにあるときにSQLが好きではありません。何か案は? –

+0

'Sql(" ALTER TABLE dbo.Accounts ADD ReconciledBalance Decimal AS SELECT SUM(Amount)FROM [トランザクション] WHERE IsReconciled = 1またはIsActive = 1またはIsVoid = 0 ");'を試してください。私はSQLでそれほど素晴らしいとは言えませんが、私はただ助けようとしています。 –

答えて

0

:(またはそれからSql("ALTER TABLE dbo.Accounts NOT SURE WHAT TO PUT HERE");を削除編集):BY句

public override void Up() 
    { 
     CreateTable(
      "dbo.Accounts_BackingTable", 
     c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      IsActive = c.Boolean(), 
      Name = c.String(), 
      Balance = c.Decimal(nullable: false, precision: 18, scale: 2), 
      HouseholdId = c.Int(), 
     }) 
     .PrimaryKey(t => t.Id) 

     Sql(@"EXECUTE('CREATE view dbo.Accounts 
with schemabinding as (SELECT 
    a.id, 
    a.isactive, 
    a.name, 
    a.balance, 
    a.householdid, 
    SUM(t.amount) AS ReconciledBalance 
FROM dbo.accounts_backingtable a 
    LEFT JOIN dbo.transactions t 
    ON t.accountid = a.id AND t.isactive = 1 AND t.isreconciled = 1 
    --It's not clear what logic you need for the join 
    --ON t.accountid = a.id AND (t.IsReconciled = 1 or t.IsActive = 1 or t.IsVoid=0) 
) 
GROUP BY a.id, 
    a.isactive, 
    a.name, 
    a.balance, 
    a.householdid')"); 

    } 

GROUPかもしれませんあなたのビューがupdateableではないことを意味します。その場合は、2つのエンティティが必要です。そのうちの1つは更新可能です。または、ストアドプロシージャを使用して変更し、ストアドプロシージャ内のSQLを変更することもできます。

NBこれは、アプリケーションではなくデータベースの内部で計算を実行しています。データベースに格納する場合は、トランザクションを作成、更新、削除するときに計算を行う必要があります。

+0

私は、[NotMapped]を使用し、必要に応じてセッターを使用してこれをやりました。計算されたフィールドを使用する正しい方法だと思うので、これを正解にします。このシナリオでは、別のテーブルのデータに基づいてフィールドを計算しようとしていましたが、これをさらに掘り下げると、これは私が見つけたものに似ています。あなたは他のテーブルからデータを選択し、合計を計算する必要があります。あなたの助けに感謝します! –

0

別のアプローチ:

public class Account 
{ 
    public Account() 
    { 
     this.Transactions = new HashSet<Transaction>(); 
    } 

    public int Id { get; set; } 
    public bool IsActive { get; set; } 
    public string Name { get; set; } 
    [Range(double.MinValue, double.MaxValue)] 
    public decimal Balance { get; set; } 
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
    [Range(double.MinValue, double.MaxValue)] 
    public decimal ReconciledBalance 
    { 
     get 
     { 
      return Transactions.Where(t => t.IsActive == true && t.IsReconciled == true).Sum(x => x.Amount) 
     } 
     private set { /* needed for EF */ } 
    } 

    //FKs 
    public int HouseholdId { get; set; } 

    //Virtual Properties 
    public virtual Household Household { get; set; }// One to one 
    public virtual ICollection<Transaction> Transactions { get; set; } 
} 

そして、うまくいけば、あなたがアップ()または下()をオーバーライドする必要はありません。あなたが代わりにテーブルのエンティティフレームワークによって期待される名前でデータベースビューにエンティティをリンクすることができ

+0

これは有効な方法ですが、常に計算を行う場合'get'では、値は決してデータベースに格納されません。 'set'と' [DatabaseGenerated(DatabaseGeneratedOption.Computed)]属性を削除して、データベースに作成されているフィールドを停止する必要があります。これは冗長です。 – Colin

+0

私はもともとあなたが示した方法でそれをやろうとしていましたが、その値をデータベースに保存します。それ以外の場合は、DatabaseGeneratedアノテーションを[NotMapped]アノテーションに置き換えて、その場で計算することができます。私はそれをDBに保存したい。ちょうど@Colinが述べたように。 –

+0

セッターがあれば、 '[NotMapped]'属性だけが必要です。 – Colin

関連する問題