94

我需要在我的数据库中有一列由数据库计算为(行总和)-(行总和 b)。我正在使用代码优先模型来创建我的数据库。

这就是我的意思:

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 中实现这一点?

4

7 回答 7

150

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

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

或者使用流畅的映射:

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

正如Matija Grcic在评论中所建议的那样,制作 property 是个好主意private set,因为您可能永远不想在应用程序代码中设置它。实体框架对私有设置器没有问题。

注意:对于 EF .NET Core,您应该使用ValueGeneratedOnAddOrUpdate因为 HasDatabaseGeneratedOption 不存在,例如:

modelBuilder.Entity<Income>().Property(t => t.Summ)
    .ValueGeneratedOnAddOrUpdate()
于 2013-03-23T10:04:42.137 回答
39
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 */ }
    }
}

参考:

于 2013-03-23T10:09:29.737 回答
32

截至 2019 年,EF 核心允许您使用 fluent 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

于 2019-02-18T17:44:32.230 回答
4

在 EF6 中,您只需将映射设置配置为忽略计算属性,如下所示:

定义模型的 get 属性的计算:

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

然后在模型配置上将其设置为忽略

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    //...
    modelBuilder.Entity<Person>().Ignore(x => x.FullName)
}
于 2020-03-06T12:00:30.450 回答
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 视图。您可以使用 Entity Framework 读取像表格一样的视图。在视图代码中,您可以进行计算或任何您想做的事情。只需创建一个视图

-- 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
于 2013-03-23T09:58:35.380 回答
1

我会通过使用视图模型来解决这个问题。例如,与其将 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 提到的,我认为将计算值保存在数据库中并不是一个好主意。只是一些想法。

于 2014-12-08T05:06:54.963 回答
-1

我在尝试使用带有字符串列“Slug”的 EF Code First 模型时偶然发现了这个问题,该模型是从另一个字符串列“Name”派生的。我采用的方法略有不同,但效果很好,所以我将在这里分享。

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

这种方法的好处是您可以自动生成 slug,而不会暴露 slug setter。.ToUrlSlug() 方法不是这篇文章的重要部分,您可以使用任何东西来完成您需要完成的工作。干杯!

于 2016-04-30T02:56:26.793 回答