在EF代码首先计算列(Calculated column in EF Code First)

2019-07-22 21:22发布

我需要通过数据库(行的总和)来计算我的数据库有一列 - (rowsb的总和)。 我使用的代码,第一个模型的创建数据库。

这里是我的意思是:

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实现这一目标?

Answer 1:

您可以创建计算列在数据库中的表。 在EF模型,你只标注与相应的属性DatabaseGenerated属性:

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

或用流利的映射:

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

正如建议Matija葛契奇和评论,这是一个好主意,使物业private set ,因为你可能永远都不想将其设置在应用程序代码。 实体框架与私营制定者没有任何问题。



Answer 2:

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

参考文献:

  • 错误在EF 4.1 DatabaseGeneratedOption.Computed
  • 在实体框架代码优先迁移计算列
  • 使用计算列


Answer 3:

一种方式是使用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视图。 您可以阅读像实体框架表的视图。 和视图代码中,你可以做计算或任何你想要的。 只要创建像图

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


Answer 4:

我会去这只要使用一个视图模型。 例如,而不是有FirstTable类作为分贝实体,你会不会更好仅仅有所谓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提到的,我不认为这将是一个不错的主意保持在数据库中的计算值。 只是一些想法。



Answer 5:

截至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 。



Answer 6:

我碰到这个问题,想有一个字符串列“弹头”的EF代码优先模式,可以从另一个字符串列“名称”导出时偶然发现。 我采取的方法也略有不同,但结果不错,所以我会在这里分享。

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

什么是对这种做法不错的就是你得到的自动生成塞,而从来没有露出塞二传手。 该.ToUrlSlug()方法是不是这个职位的重要组成部分,你可以使用任何在它的地方,你需要做的工作。 干杯!



文章来源: Calculated column in EF Code First