Need Help With Application Design - c#

So, I'd love some feedback on the best way to design the classes and store the data for the following situation:
I have an interface called Tasks that looks like this:
interface ITask
{
int ID{ get; set;}
string Title {get; set;}
string Description{get; set;}
}
I would like the ability to create different types of Tasks depending on who is using the application...for example:
public class SoftwareTask: ITask
{
//ITask Implementation
string BuildVersion {get; set;}
bool IsBug {get; set;}
}
public class SalesTask: ITask
{
//ITask Implementation
int AccountID {get; set;}
int SalesPersonID {get; set;}
}
So the way I see it I can create a Tasks table in the database with columns that match the ITask interface and a column that shoves all of the properties of more specific tasks in a single column (or maybe even serialize the task object into a single column)
OR
Create a table for each task type to store the properties that are unique to that type.
I really don't like either solution right now. I need to be able to create different types of Tasks ( or any other class) that all share a common core set of properties and methods through a base interface, but have the ability to store their unique properties in a fashion that is easy to search and filter against without having to create a bunch of database tables for each type.
I've starting looking into Plug-In architecture and the strategy pattern, but I don't see where either would address my problem with storing and accessing the data.
Any help or push in the right direction is greatly appreciated!!!

Your second approach (one table per type) is the canonical way to solve this problem - while it requires a bit more effort to implement it fits better with the relational model of most databases and preserves a consistent and cohesive representation of the data. The approach of using one table per concrete type works well, and is compatible with most ORM libraries (like EntityFramework and NHibernate).
There are, however, a couple of alternative approaches sometimes used when the number of subtypes is very large, or subtypes are created on the fly.
Alternative #1: The Key-Value extension table. This is a table with one row per additional field of data you wish to store, a foreign key back to the core table (Task), and a column that specifies what kind of field this is. It's structure is typically something like:
TaskExt Table
=================
TaskID : Number (foreign key back to Task)
FieldType : Number or String (this would be AccountID, SalesPersonID, etc)
FieldValue : String (this would be the value of the associated field)
Alternative #2: The Type-Mapped Extension Table. In this alternative, you create a table with a bunch of nullable columns of different data types (numbers, strings, date/time, etc) with names like DATA01, DATA02, DATA03 ... and so on. For each kind of Task, you select a subset of the columns and map them to particular fields. So, DATA01 may end up being the BuildVersion for a SoftwareTask and an AccountName for a SalesTask. In this approach, you must manage some metadata somewhere that control which column you map specific fields to. A type-mapped table will often look something like:
TaskExt Table
=================
TaskID : Number (foreign key back to task)
Data01 : String
Data02 : String
Data03 : String
Data04 : String
Data05 : Number
Data06 : Number
Data07 : Number
Data08 : Number
Data09 : Date
Data10 : Date
Data11 : Date
Data12 : Date
// etc...
The main benefit of option #1 is that you can dynamically add as many different fields as you need, and you can even support a level of backward compatibility. A significant downside, however, is that even simple queries can become challenging because fields of the objects are pivoted into rows in the table. Unpivoting turns out to be an operation that is both complicated and often poorly performing.
The benefits of option #2 is that it's easy to implement, and preserves a 1-to-1 correspondence betweens rows, making queries easy. Unfortunately, there are some downsides to this as well. The first is that the column names are completely uninformative, and you have to refer to some metadata dictionary to understand which columns maps to which field for which type of task. The second downside is that most databases limit the number of columns on a table to a relatively small number (usually 50 - 300 columns). As a result, you can only have so many numeric, string, datetime, etc columns available to use. So if you type ends up having more DateTime fields than the table supports you have to either use string fields to store dates, or create multiple extension tables.
Be forewarned, most ORM libraries do not provide built-in support for either of these modeling patterns.

You should probably take a lead from how ORMs deal with this, like TPH/TPC/TPT
Given that ITask is an interface you should probably go for TPC (Table per Concrete Type). When you make it a baseclass, TPT and TPH are also options.

Related

How to Remove a Attribute of a Property in a Class

I want to do some changes in a table that is already exist(i am using sqlite). I want to remove a Attribute of a property in a class. Remove [Required] attribute. How can i do that, what should i change, should i some changes in DbContext or migration folder or what commands can i use in package manager console.
public class Appointment
{
[Required]
[MaxLength(50)]
public string Company { get; set; }
This is a good example of why it is better to use fluent API then attributes to specify your database: you want the same class to be used in a different database.
The DbContext defines the database: what tables are in it, how do the tables relate towards each other, what classes do represent the tables, and what are the constraints to the tables.
For instance, maybe in one database you want Company to have a MaxLength of 50 characters, in another database you might desire a length of 100 characters. Some databases need a simple DateTime, others require a DateTime2. Or maybe you want a different precision for your decimals?
Hence it is usually better to specify the database statistics where it belongs: in the definition of the database, which is the DbContext.
Back to your question
It depends a bit on the entity framework that you are using on how the database reacts if during migration you use remove the Required attribute and move it to fluent API. I guess it is best to experiment with it.
In OnModelCreating, or the migration equivalent of it, you will have something like:
var entityAppointment = modelBuilder.Entity<Appointment>();
var propertyCompany = entityAppointment.Property(appointment => appointment.Company);
propertyCompany.IsOptional()
.HasMaxLength(50)
...; // other non-default specifications of Company
// like columnName, IsUnicode, etc
When migrating the statements might be little different, but I guess you get the gist.

Is it a good idea to store classes as settings items in sql?

I am doing this project in c# and when designing a database, i am using a rule that each class is basically sql table (at least the class that has to be persisted).
Since some classes are purely used to define business settings and the classes are rather flat, I am curios does it make any sense to do something like this..
Transform business layer class
class Contact
{
public string Name {get;set;}
public string PhoneNumber {get;set;}
public bool AcceptsTextMessages {get;set;}
public bool AllowedHoursForTextMessagesStart {get;set;}
public bool AllowedHoursForTextMessagesEnd {get;set;}
public List<DayOfWeek> SendMessagesOnlyOnWorkdays {get;set;}
}
to a data layer class that look something like (and persist it in sql)
public Settings
{
public ID {get;set}
public Name {get;set}
public Value {get;set;}
}
with real life data
ID Name Value
1 Name John Doe
2 PhoneNumber 01234657
3 ExceptsTextMessages true
4 AllowedHoursForTextMessagesStart 0
5 AllowedHoursForTextMessagesEnd 24
6 SendMessagesOnlyOnDays 1,2,3,4,5
The primary reason for this is to have one settings table instead of having as many tables as classes, possibly easier class modification, easier manipulation of properties between classes (in case there is a business logic need to move one property from one class to another)
Decomposing your objects into IDs and attribute-value pairs is one of those techniques that's sometimes extremely useful. EAV data is much more complicated to manage than a flat table with individual columns, so it's not something to implement lightly.
Given what you've posted, I probably wouldn't. All the fields you have seem reliably relevant to being-a-contact and unlikely to require changing around dynamically in production (since one starts or stops accepting text messages, rather than ascending to a plane of existence where text messages are epistemologically irrelevant).
Even if it made sense to represent certain fields as pairs, I'd only do it for those fields: keep a users table with a primary key and the essential data, then put the rest off in an EAV table with a foreign key relationship to users.

Complex type fields

I want to separate contact information in my User table, and I am thinking of two ways of doing it.
First is to make a new table and then my User table references that table through foreign key.
Or to make complex type which is part of the User table, by adding [ComplexType] annotation to Address field.
This is Address class, just an example:
public class Address
{
public string City {get; set;}
public string Street { get; set; }
public string Country { get; set; }
public string Phone { get; set; }
}
What do you recommend me to do? Which is better way?
If you ask this quesition for a clean coder then just he will answer you with two entities/classes SRP
http://www.oodesign.com/single-responsibility-principle.html
If you ask the same quesition for a database delevoper then his answer will be no joins use complex types.
Me as a developer I find Complex Types has some limitation and I will never use them.
Here I will copy from http://weblogs.asp.net/manavi/associations-in-ef-4-1-code-first-part-2-complex-types the pros and cons of the complex types:
There are three important limitations to classes mapped as Complex Types:
Shared References is Not Possible:
The Address Complex Type doesn’t have its own database identity (primary key) and so can’t be referred to by any object other than the containing instance of User (e.g. a Shipping class that also needs to reference the same User Address, cannot do so).
No Elegant Way to Represent a Null Reference:
As we saw there is no elegant way to represent a null reference to an Address. When reading from database, EF Code First always initialize Address object even if values in all mapped columns of the complex type are null.
Lazy Loading of Complex Types is Not Possible:
Note that EF always initializes the property values of a complex type right away, when the entity instance that holds the complex object is loaded. EF does not support lazy loading for complex types (same limitation also exists if you want to have lazy loading for scalar properties of an entity). This is inconvenient when we have to deal with potentially large values (for example, a property of type byte[] on the Address complex type which has been mapped to a VARBINARY column on Users table and holds an image of the location described by the Address.).
Best Practices you can read it in the given link above.
Well there's no perfect choice for this, it depends on the multiplicity: if a user have multiple addresses then you need to go with the foreign key option, if a user has only one address the you can either add the address fields to the user fields (simple) or use [ComplexType]
Your First (Separate table) choice is better, because single user have multiple contact records then it is better to handle this in separate table by foreign reference.
it is also better for changes in its contact info , means permanent address , postal address , resident contact no , self contact no and so on ,you can easily updated this in separate table ,
and this is the good practice of normalization in database

L2S Approach for Interface Property

We're using L2S and we have a class like this:
public class HumanContainer
{
public List<IHuman> Humans { get; set; }
public string SomeOtherProperty { get; set; }
}
Our database has tables like this:
HumanContainer
- Geek
We've only had one type of Human so far (Geek). And when we send/retrieve HumanContainers to/from the DB, we know to treat them as Geeks. Now that we need a second Human (Athlete), we have a choice to make for how to implement this.
One option is to create another table (Athlete) in the DB:
HumanContainer
- Geek
- Athlete
For every new concrete Human like this, we'll need to loop through HumanContainer.Humans, detect the type, add it to the appropriate EntitySet<>, then save.
Another option is to have only one table for all Humans:
HumanContainer
- Humans
If we do that, then we'll need something like an XML column where we serialize the Human into its specific type and store it in that column. Then we'll need to deserialize that column when retrieving the data.
Is one of the approaches recommended? I'm curious to know how people have been handling this situation. Is there a third approach that I haven't listed here?
What it sounds like you are trying to do is represent inheritance in a relational database. Guy Burstein has a pair of great articles on this subject: How To: Model Inheritance in Databases and Linq to SQL Inheritance.
As I understand properly your question, In your case It's possible to have different type of humans in future. You can try following solution.
Solution 1:
As you mentioned only create One Table in Database 'Humas' and serialize the Human into specific Type and store it in that column and deserialize that column when retrieving the data. This solution seems good because If need to any Human type in future we don't need to change database design. and easy to manage.
But The dis advantage of this solution is that if application required only Geek Humans type then first need to retrieve column data and deserialize it and after that we can find Geek Human type.
Solution 2:
Create Two table in database.
1) HumanType : for save Type of human (Geek, Athlete, or any other Type)
2) Human : storing Human information. This table contain reference key of HumanType.
The Advantage of this solution is that you can easily fire query based on requirement (e.g Only Geek Type Human easily fetched from table). and if any new Human Type come then one entry required to enter in HumanType Database.

Is there a .NET Polymorphic Data Framework

I'm beginning work on a new project that's would be much easier if there was some way to make different data models polymorphic. I'm looking at using the Entity Framework 4.0 (when it's released), but have been unable to determine if it will actually be able to work.
Here's the basic scenario. I'm implemented a comment system, and would like to be able to connect it to many different types of models. Maybe I want comments on a person's profile, and comments on a webpage. The way I would do this in the past is to create relationships between the person table and the comment table separately from the relationship between the webpage table and the comment table. I think this leads to an overly complicated table structure in the database, however.
It would be best if I could just be able to add an interface to the objects I want comments on, and then simplify the table structure in the database to a single relationship.
The problem I'm running into is that I don't seem to know the right terminology in order to find information about how to do this type of thing. Any help anyone can provide would be greatly appreciated.
If you design your "comments table" to be comment-type-agnostic (just the basics, like an id, date & time, and text content), you can then use a single additional table that maps them all.
public interface ICommentable
{
int CommentTypeCode
int Id
...
}
Now that mapper table contains columns:
comment_type_code
target_object_id
comment_id
Your comments all go in one table, with an Id
Your various "target objects" must all have an Id of the same type
Now you can arbitrarily add new "commentable" objects to your system without changing the comments table or the mapper table -- just assign it a new type code and create the table with the requisite Id column.
I accomplish this with LinqToSql and partial classes. For each class that I want to implement an interface, I go to create a non-tool-generated file that contains part of the partial class that declares the class to implement the interface.
For example:
Generated code:
// this code is generated by a tool blah blah
partial class FooComment {
// all the generated crap
string Author {
// ...
}
// etc
}
The interface:
interface IComment{
string Author{ get; }
// etc
}
My code:
// lovingly hand-written by me
partial class FooComment : IComment {
}
Now, if you want to cast any group of FooComments to IComment, use the Cast linq extension method:
db.FooComments.Cast<IComment>()

Categories