我已将计算字段(Active
和CreditsLeft
)直接添加到我的CodeFirst实体类中。在CF实体类中添加计算字段逻辑是否是个好主意?
public class User : Entity
{
public User()
{
Id = Helper.GetRandomInt(9);
DateStamp = DateTime.UtcNow;
TimeZone = TimeZoneInfo.Utc.Id;
}
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
[MaxLength(50)]
public string Email { get; set; }
[Required]
[MaxLength(50)]
public string Password { get; set; }
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(50)]
public string LastName { get; set; }
[Required]
public DateTime DateStamp { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual ICollection<Statistic> Statistics { get; set; }
public virtual ICollection<Notification> Notifications { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public bool Active
{
get
{
return Orders.Any(c => c.Active && (c.TransactionType == TransactionType.Order || c.TransactionType == TransactionType.Subscription));
}
}
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public int CreditsLeft
{
get
{
return Orders.Sum(p => p.Credits != null ? p.Credits.Value : 0);
}
}
}
答案 0 :(得分:1)
在CF实体类中添加计算字段逻辑是否是个好主意?
当然,你可以做到这一点,但有一些事情你必须要照顾。
首先,由业务逻辑计算的属性的属性不是[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
,因为这表示该值是在数据库中计算的(如在计算列中)。您应该使用[NotMapped]
属性标记该属性。这告诉实体框架忽略数据库映射中的属性。
其次,由于两个属性都使用Orders
,因此必须确保在访问任一属性时加载订单或者可以延迟加载。因此,您可能希望使用User
语句(Include
)加载Include(user => user.Orders)
。否则,在访问Active
或CreditsLeft
时,您必须确保上下文仍然有效。
第三,您无法直接在EF LINQ查询中处理属性,如
db.Users.Select(u => u.Active);
因为EF会抛出一个不知道Active
的异常。您只能在内存中的物化用户对象上处理属性。