Tomas
Tomas

Reputation: 18117

EF CodeFirst computed field in CF entity class

I have added computed fields(Active and CreditsLeft) directly into my CodeFirst entity class. Is it good idea to add computed field logic inside CF Entity class?

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

    }

Upvotes: 1

Views: 196

Answers (1)

Gert Arnold
Gert Arnold

Reputation: 109185

Is it good idea to add computed field logic inside CF Entity class?

Sure, you can do this, but there are a few things you must take care of.

First, the attribute for a property that is computed by business logic is not [DatabaseGenerated(DatabaseGeneratedOption.Computed)], because this indicates that the value is computed in the database (as in a computed column). You should mark the property by the [NotMapped] attribute. This tells Entity Framework to ignore the property in database mapping.

Second, since both properties use Orders, you must make sure that the orders are loaded or can be lazy loaded when either property is accessed. So you may want to load Users with an Include statement (Include(user => user.Orders)). Or else you must ensure that the context is still alive when Active or CreditsLeft is accessed.

Third, you can't address the properties directly in an EF LINQ query, as in

db.Users.Select(u => u.Active);

because EF will throw an exception that it doesn't know Active. You can address the properties only on materialized user objects in memory.

Upvotes: 1

Related Questions