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>()
Related
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.
I have been tasked with doing the data mapping for a C# api, and it is one which features some more complex data relationships than I typically have had experience with (I have worked with foreign keys without data cascades, and have not validated data according to subclass before).
I am unsure of how to correctly institute the data mapping I have been tasked with - I could surely come up with something but I would rather not end up committing anti-patterns to the repo.
There is a parent class, let's say, Treat. All treats must have certain ingredients:
public class Treat
{
public ICollection<Ingredient> Ingredients { get; }
// Other members omitted
}
public class Ingredient
{
public Ingredient() { }
// Other members omitted
}
public class Sugar : Ingredient
{
public Sugar() { }
// Other members omitted
}
So let's say Treats are allowed to have (but don't have to) Sugar and Artificial Flavours only as ingredients. We define more ingredients for specific treats by referring to subclasses:
public class Chocolate : Treat
{
// Implementation omitted
}
Chocolate, let's say, can also have Cocoa : Ingredient and Flour : Ingredient.
How can I implement this mapping? I was going to store everything in columns of the one table and validate in the api endpoint controllers originally but I have been asked to reflect the validation rules in the class structure.
Your example code only contains a N:M or Many to Many relationship. Every Treat (N) can have several Ingredients (M). But each ingredient (M) can also be used by several Treats (N). Those are very common, very standart problems. They can not be resolved really, only disolved into two smaler Problems.
On the DB side N:M Relationships are usually disolved into a N:1 and 1:N relationship, using a middle table (TreatIngridients). A table consisting of nothing but a Primary Key and two Foreign Keys. I am not sure how to implement a N:M on the class side, but it is a exceedingly common problem of code first. So I quickly found one link to EF:
https://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
Apparently both Clases will contain a List of their counterparts. This setup of cross references pains every programmer part of my brain (I hope I never get to do a OUTER JOIN on that. Keeping both lists in synch would be a nightmare). However it would be easily build from a Databse. You either build your Instances in Memory from the Ignredient side or the Treat side. The other will be mostly static data (with ingredients being propably usually the other side)
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.
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.
In my line of business we have Products. These products can be modified by a user by adding Modifications to them. Modifications can do things such as alter the price and alter properties of the Product. This, to me, seems to fit the Decorator pattern perfectly.
Now, envision a database in which Products exist in one table and Modifications exist in another table and the database is hooked up to my app through the Entity Framework. How would I go about getting the Product objects and the Modification objects to implement the same interface so that I could use them interchangeably?
For instance, the kind of things I would like to be able to do:
Given a Modification object, call .GetNumThings(), which would then return the number of things in the original object, plus or minus the number of things added by the modification.
This question may be stemming from a pretty serious lack of exposure to the nitty-gritty of EF (all of my experience so far has been pretty straight-forward LOB Silverlight apps), and if that's the case, please feel free to tell me to RTFM.
Thanks in advance!
Edit:
It would also be nice if, given a third table, linking a Products to Modifications (one-to-many) it could reconstruct the decorated object (I realize that this is likely way out of bound for the EF to do automatically). How would you recommend going about this, and where would that code reside? Would it be part of the EF classes or would every entity I received from the DB need to be passed through some sort of "builder" to construct a decorated object from a Product and its list of Modifications?
I am not entirely sure if I understood your question correctly, but here goes: You can create partial classes to those defined in your EF model. You could define a common interface and use the partial classes to implement that interface.
For example:
public interface IProduct{
public int GetNumThings();
}
public partial class Product : IProduct{
public int GetNumThings()
{
...
}
}
public partial class Modification: IProduct{
public int GetNumThings()
{
...
}
}