我需要在我的数据库中有一列由数据库计算为(行数之和) - (行数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中实现这一目标?
答案 0 :(得分:119)
您可以在数据库表中创建computed columns。在EF模型中,您只需使用DatabaseGenerated
属性注释相应的属性:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public double Summ { get; private set; }
或者使用流畅的映射:
modelBuilder.Entity<Income>().Property(t => t.Summ)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)
正如Matija Grcic和评论中所建议的那样,建立属性private set
是个好主意,因为您可能永远不想在应用程序代码中设置它。私有制定者没有实体框架。
答案 1 :(得分:27)
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 */ }
}
}
参考文献:
答案 2 :(得分:2)
一种方法是使用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
答案 3 :(得分:2)
截至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。
答案 4 :(得分:2)
在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)
}
答案 5 :(得分: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提到我不认为将计算值保存在数据库中是个好主意。只是一些想法。
答案 6 :(得分:-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()方法不是这篇文章的重要部分,您可以使用任何代替它来完成您需要完成的工作。干杯!