I am writing an MVC4 application to track documents we have on file for our clients. I'm using code first, and have created models for my objects (Company, Document, etc...). I am now faced with the topic of document expiration.
Business logic dictates certain documents will expire a set number of days past the document date. For example, Document A might expire in 180 days, Document 2 in 365 days, etc... I have a class for my documents as shown below (simplified for this example).
What is the best way for me to create a lookup for expiration values? I want to specify documents of type DocumentA expire in 30 days, type DocumentB expire in 75 days, etc... I can think of a few ways to do this:
- Lookup table in the database I can query
- New property in my class (DaysValidFor) which has a custom getter that returns different values based on the DocumentType
- A method that takes in the document type and returns the number of days
and I'm sure there are other ways I'm not even thinking of. My main concern is a) not violating any best practices and b) maintainability. Are there any pros/cons I need to be aware of for the above options, or is this a case of "just pick one and run with it"?
One last thought, right now the number of days is a value that does not need to be stored anywhere on a per-document basis -- however, it is possible that business logic will change this (i.e., DocumentA's are 30 days expiration by default, but this DocumentA associated with Company XYZ will be 60 days because we like them). In that case, is a property in the Document class the best way to go, seeing as I need to add that field to the DB?
namespace Models
{
// Types of documents to track
public enum DocumentType
{
DocumentA,
DocumentB,
DocumentC // etc...
}
// Document model
public class Document
{
public int DocumentID { get; set; }
// Foreign key to companies
public int CompanyID { get; set; }
public DocumentType DocumentType { get; set; }
// Helper to translate enum's value to an integer for DB storage
[Column("DocumentType")]
public int DocumentTypeInt
{
get { return (int)this.DocumentType; }
set { this.DocumentType = (DocumentType)value; }
}
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM-dd-yyyy}", ApplyFormatInEditMode = true)]
public DateTime DocumentDate { get; set; }
// Navigation properties
public virtual Company Company { get; set; }
}
}
2 Answers 2
If DaysValidFor
is a property of the document type, then put it in the DocumentType
table, and look it up or join it with the Documents
table.
If DaysValidFor
can be customized, add a DaysValidFor
field to the Documents table, and use the DaysValidFor
in the DocumentType
table as a default value when you are creating a new Document
record.
Rationale
By having a DocumentType
table from the start, you provide a container by which all sorts of other features become possible as a function of that document type. You also avoid a redesign when you find out you need a DocumentType table, and you didn't provide one. Not every domain object needs such a type table, but documents are naturally organized into categories, so it's a good fit here.
You can have a DaysValidFor
method in your repository if you want one. Pass it the DocumentID
, and look the value up from the Documents
table.
If you think in terms of classes instead of tables (i.e. "code first"), just substitute the word "class" for the word "table" in the two paragraphs above.
-
Thanks for the answer -- DocumentType does not have a separate class/table currently...it is currently an enum. I have no problem changing that to a lookup table (my option #1 listed in the question), just trying to see what the best design option would be...Jim– Jim2013年10月01日 17:37:15 +00:00Commented Oct 1, 2013 at 17:37
-
Having it as a lookup table from the start is going to avoid some problems down the road. You're going to find out that you will need some other attributes attached to a document type, so you're going to need a
DocumentType
table anyway. But go ahead and put theDaysValidFor
field in theDocument
table also. Having it there means you don't have to join theDocumentType
table if you just wantDaysValidFor
.Robert Harvey– Robert Harvey2013年10月01日 17:39:31 +00:00Commented Oct 1, 2013 at 17:39 -
OK, so I would have a DaysValidFor field in the Documents table to store the per-document value, and then a lookup table DocumentTypes that has a list of doc types and default values I can use for the days valid value, right?Jim– Jim2013年10月01日 17:43:44 +00:00Commented Oct 1, 2013 at 17:43
-
Yes, that's right.Robert Harvey– Robert Harvey2013年10月01日 17:45:20 +00:00Commented Oct 1, 2013 at 17:45
-
@RobertHarvey I'm wondering if that does not break YAGNI? I like to start with as simple as possible - hardcoded values, enums, etc. and if it really has rapidly changing values, bring in database table/editing/etc - because each additional table brings some complexity.Giedrius– Giedrius2013年10月03日 11:35:27 +00:00Commented Oct 3, 2013 at 11:35
Hum, to each one his own way to see things, but to me this has nothing to do with C# MVC 4, and everything to do with the database itself, as this is linked to the data, not the way they are accessed.
I think I would create a View (SQL View, not MVC...) with a calculated column for the expiration date. This way you can use any criteria you want, check if documents are linked, the company, the type of document, just anything you need, and change those criterias as many time as needed, without any change in the MVC application.
I know you can create stored procedures with Code First, I am not too sure bout Views, but really from my point of view this belongs into the database, so that's what I would be looking to do.
-
1@Giedrius Unless I totally misunderstand, YAGNI has nothing to say about database design, but with coding principles. I doubt mixing the 2 bring good results.BernardG– BernardG2013年11月02日 17:04:10 +00:00Commented Nov 2, 2013 at 17:04
-
Why on earth would you ever be calculating business logic in a data store? All he has to do is calculate an expiration date upon document creation and save that. The actual lookup value should either be drawn from a table or config file.Mr Cochese– Mr Cochese2013年11月02日 20:13:11 +00:00Commented Nov 2, 2013 at 20:13
-
Again, from my point of view, this is NOT (business) logic, but data. Expiration date is an attribute of a document, just as its title, number of words and author. The fact that it is calculated (as a number of words is), does not change its nature.BernardG– BernardG2013年12月01日 09:27:35 +00:00Commented Dec 1, 2013 at 9:27