Ich muss eine Spalte in meiner Datenbank haben, die von der Datenbank als (Summe der Zeilen) - (Summe der Zeilen b) berechnet wird. Ich verwende das Code-First-Modell, um meine Datenbank zu erstellen.
Folgendes 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 dies in EF CodeFirst erreichen?
ValueGeneratedOnAddOrUpdate()
daHasDatabaseGeneratedOption
diese nicht vorhanden ist. Ansonsten tolle Antwort.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:
quelle
/* do your sum here */
nicht zutrifft. Wenn die Eigenschaft innerhalb der Klasse berechnet wird, sollte sie als kommentiert werden[NotMapped]
. Der Wert stammt jedoch aus der Datenbank, daher sollte es sich nur um eine einfacheget
Eigenschaft handeln.Ab 2019 können Sie mit EF Core Spalten auf saubere Weise mit der fließenden API berechnen:
Angenommen, dies
DisplayName
ist die berechnete Spalte, die Sie definieren möchten. Sie müssen die Eigenschaft wie gewohnt definieren, möglicherweise mit einem privaten Eigenschaftenzugriff, um die Zuweisung zu verhindernpublic 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 .
quelle
In EF6 können Sie die Zuordnungseinstellung einfach so konfigurieren, dass eine berechnete Eigenschaft wie folgt ignoriert wird:
Definieren Sie die Berechnung für die get-Eigenschaft Ihres Modells:
public class Person { // ... public string FirstName { get; set; } public string LastName { get; set; } public string FullName => $"{FirstName} {LastName}"; }
Stellen Sie dann ein, dass die Modellkonfiguration ignoriert wird
protected override void OnModelCreating(ModelBuilder modelBuilder) { //... modelBuilder.Entity<Person>().Ignore(x => x.FullName) }
quelle
Eine Möglichkeit ist dies 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 dies innerhalb Ihres POCO-Objekts tun
public class FirstTable
, aber ich würde es nicht vorschlagen, da ich denke , dass es kein gutes Design ist.Ein anderer Weg wäre die Verwendung einer SQL-Ansicht. Sie können eine Ansicht wie eine Tabelle mit Entity Framework lesen. Und innerhalb des Ansichtscodes können Sie Berechnungen durchführen oder was auch immer Sie wollen. 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
quelle
Ich würde dies tun, indem ich nur ein Ansichtsmodell verwende. Anstatt beispielsweise die FirstTable-Klasse als Datenbankentität zu haben, wäre es nicht besser, nur eine Ansichtsmodellklasse namens FirstTable zu haben und dann eine Funktion zu 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 und die berechnete Summe zurückgibt:
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; }
Grundsätzlich das gleiche wie bei einer SQL-Ansicht und wie bei @Linus erwähnt, halte ich es nicht für eine gute Idee, den berechneten Wert in der Datenbank zu belassen. Nur ein paar Gedanken.
quelle
I don't think it would be a good idea keeping the computed value in the database
- insbesondere, wenn Sie Azure SQL verwenden, das bei hoher Last zu einem Deadlock führt.Ich bin auf diese Frage gestoßen, als ich versucht habe, ein EF Code First-Modell mit einer Zeichenfolgenspalte "Slug" von einer anderen Zeichenfolgenspalte "Name" abzuleiten. Der Ansatz, den ich gewählt habe, war etwas anders, hat aber gut funktioniert, deshalb werde ich ihn hier teilen.
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; }
Das Schöne an diesem Ansatz ist, dass Sie die automatische Schneckengenerierung erhalten, ohne den Schneckensetzer freizulegen. Die .ToUrlSlug () -Methode ist nicht der wichtige Teil dieses Beitrags. Sie können an ihrer Stelle alles verwenden, um die Arbeit zu erledigen, die Sie erledigen müssen. Prost!
quelle
Slug
zuName
? Wie derzeit geschrieben, sollte derName
Setter nicht einmal kompilieren.