96 votes

Colonne calculée dans EF Code First

J'ai besoin d'avoir une colonne dans ma base de données calculée par la base de données comme (somme des lignes) - (somme des lignesb). J'utilise le modèle code-first pour créer ma base de données.

Voici ce que je veux dire :

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

Comment puis-je réaliser cela dans EF CodeFirst ?

155voto

Gert Arnold Points 27642

Vous pouvez créer colonnes calculées dans les tables de votre base de données. Dans le modèle EF, il suffit d'annoter les propriétés correspondantes avec l'attribut DatabaseGenerated attribut :

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

Ou avec une cartographie fluide :

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

Comme le suggère Matija Grcic et dans un commentaire, c'est une bonne idée de rendre la propriété private set car vous ne voudrez probablement jamais le définir dans le code de l'application. Entity Framework n'a aucun problème avec les setters privés.

Note : Pour EF .NET Core, vous devez utiliser ValueGeneratedOnAddOrUpdate parce que HasDatabaseGeneratedOption n'existe pas, par exemple :

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

39voto

Matija Grcic Points 3905
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 */ }
    }
}

Références :

34voto

Pier Points 622

À partir de 2019, EF core vous permet d'avoir des colonnes calculées de manière propre avec l'API fluente :

Supposons que DisplayName est la colonne calculée que vous souhaitez définir, vous devez définir la propriété comme d'habitude, éventuellement avec un accesseur de propriété privée pour éviter de l'affecter.

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

Ensuite, dans le constructeur de modèle, adressez-le avec la définition de la colonne :

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

Pour plus d'informations, consultez le site MSDN .

4voto

Fernando Vieira Points 633

Dans EF6, vous pouvez simplement configurer le paramètre de mappage pour ignorer une propriété calculée, comme ceci :

Définissez le calcul sur la propriété get de votre modèle :

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

Ensuite, il faut l'ignorer dans la configuration du modèle

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

3voto

Linus Caldwell Points 4816

L'un des moyens est de le faire avec 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;

Vous pouvez le faire dans le cadre de votre objet POCO public class FirstTable mais je ne le suggérerais pas, car Je pense ce n'est pas une bonne conception.

Un autre moyen serait d'utiliser une vue SQL. Vous pouvez lire une vue comme une table avec Entity Framework. Et dans le code de la vue, vous pouvez faire des calculs ou ce que vous voulez. Il suffit de créer une vue comme

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X