wake-up-neo.com

Berechnete Spalte in EF-Code zuerst

Ich muss eine Spalte in meiner Datenbank haben, die von der Datenbank als (Summe der Zeilen) - (Summe der Zeilenb) berechnet wird. Ich verwende Code-First-Modell, um meine Datenbank zu erstellen.

Hier meine ich:

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)
}

Wie kann ich das in EF CodeFirst erreichen?

65
CodeDemen

Sie können berechnete Spalten in Ihren Datenbanktabellen erstellen. Im EF-Modell kommentieren Sie einfach die entsprechenden Eigenschaften mit dem Attribut DatabaseGenerated:

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

Oder mit fließendem Mapping:

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

Wie von Matija Grcic und in einem Kommentar vorgeschlagen, ist es eine gute Idee, die Eigenschaft private set zu erstellen, da Sie sie wahrscheinlich niemals im Anwendungscode festlegen möchten. Entity Framework hat keine Probleme mit privaten Setters.

117
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 */ }
    }
}

Verweise: 

26
Matija Grcic

Eine Möglichkeit ist es mit 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;

Sie können es in Ihrem POCO-Objekt public class FirstTable tun, aber ich würde nicht vorschlagen, weil ich denke es ist kein gutes Design.

Eine andere Möglichkeit wäre die Verwendung einer SQL-Ansicht. Sie können eine Ansicht wie eine Tabelle mit Entity Framework lesen. Innerhalb des Ansichtscodes können Sie Berechnungen durchführen oder was immer Sie möchten. Erstellen Sie einfach eine Ansicht wie

-- 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

Ich würde dies mit einem Ansichtsmodell tun. Anstelle der Klasse FirstTable als DB-Entität wäre es nicht besser, wenn Sie eine Ansichtsmodellklasse namens FirstTable haben und dann eine Funktion haben, mit der diese Klasse zurückgegeben wird, die die berechnete Summe enthält. Zum Beispiel wäre Ihre Klasse nur: 

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

Und dann hätten Sie eine Funktion, die Sie aufrufen, um die berechnete Summe zurückzugeben:

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;
}

Im Grunde dasselbe wie eine SQL-Ansicht und als @Linus erwähnt, denke ich nicht, dass es eine gute Idee wäre, den berechneten Wert in der Datenbank zu behalten. Nur ein paar Gedanken.

1
craigvl

Seit 2019 können Sie mit EF Core Spalten mit der fließenden API auf saubere Weise berechnen:

Angenommen, DisplayName ist die berechnete Spalte, die Sie definieren möchten. Sie müssen die Eigenschaft wie üblich definieren, möglicherweise mit einem privaten Eigenschaftszugriffscode, um die Zuweisung zu verhindern

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; }
}

Adressieren Sie es dann im Model Builder mit der Spaltendefinition:

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

Weitere Informationen finden Sie unter MSDN .

0
Pier