Tip 42 – How to create a dynamic model using Code-Only
Background:
When we give examples of how to use Code-Only we always start with a strongly typed Context derived from ObjectContext. This class is used to bootstrap the model.
For example this (property bodies omitted for simplicity sake):
public class MyContext : ObjectContext
{
public ObjectSet<Category> Categories { get; }
public ObjectSet<Product> Products { get; }
}
Tells CodeOnly that to bootstrap a model with 2 EntitySets, a set of Category entities called Categories, and a set of Product entities called Products.
Then if necessary you can further refine the model by manipulating the ContextBuilder.
Problem:
But what if you don’t have a strongly typed Context class?
What if you make a determination at runtime that you need a model, there isn't an appropriate strongly typed Context class lying around.
A customer asked me this very question earlier today.
Solution:
It turns out you can use ObjectContext directly. When you do this though Code-Only knows nothing about the model. But that isn’t that bad all you need to do is explicitly tell Code-Only about all the things it would normally learn from the strongly typed context.
For example this:
public ObjectSet<Person> People { get; }
Can be converted into this:
var builder = new ContextBuilder<ObjectContext>();
builder.RegisterSet<Person>(“People”);
Nifty huh?
End to end example:
This example, persists a Person (BillG) to the database and retrieves it again, all without a strongly typed ObjectContext:
First the Person class (which is POCO):
public class Person
{
public int ID { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
}
And now the code to setup the ObjectContext:
// Create the contextbuilder, and tell it about the People set.
var builder = new ContextBuilder<ObjectContext>();
builder.RegisterSet<Person>("People");
// Create a connection
string connstr = @"Data Source=.\SQLEXPRESS;Initial Catalog=PeopleDb;Integrated Security=True;Pooling=False;MultipleActiveResultSets=True";
var conn = new SqlConnection(connstr);
// Create an ObjectContext from the builder
using (ObjectContext ctx = builder.Create(conn))
{
// Create the database if it doesn’t already exist
if (!ctx.DatabaseExists())
ctx.CreateDatabase();
// Create Bill
Person p = new Person {
ID = 1,
Firstname = "Bill",
Surname = "Gates"
};
// Add Bill to the context
// UPDATE: thanks to danny for the simplification
ctx.CreateObjectSet<Person>().AddObject(p);
using the general purpose
// AddObject method.
// The only tricky part is the EntitySet name with must
// be qualified with the the container name,
// in this case is ObjectContext.
ctx.AddObject("ObjectContext.People", p);
ctx.SaveChanges();
// Issue a query against the People set.
var bill = (from person in ctx.CreateObjectSet<Person>()
where person.Firstname == "Bill"
select person).Single();
// Make and Save a change.
bill.Firstname = "William";
ctx.SaveChanges();
}
Pretty easy considering it isn’t strongly typed.
Comments
- Anonymous
November 09, 2009
Hi!How about an RegisterSet that takes a Type instead of a generic version? Then You could register this dynamically.I have put up an similar example that could be found:http://danielwertheim.wordpress.com/2009/11/09/entity-framework-4-ctp-2-clean-code-with-poco-entities///Daniel - Anonymous
November 09, 2009
The comment has been removed - Anonymous
November 09, 2009
Just curious, why most of you code snippet uses ObjectSet instead of IObjectSet, the same is true for IList<T> and List<T>. I did a blog post on this issue which you find interesting: http://weblogs.asp.net/rashid/archive/2009/09/13/shrinkr-url-shrinking-service-developed-with-entity-framework-4-0-unity-asp-net-mvc-and-jquery-part-2.aspx - Anonymous
November 09, 2009
@Kazi,No real reason, you could obviously do this with IObjectSet and IList etc.But for this post I wasn't focusing on testability.Thanks for the link.Alex - Anonymous
November 12, 2009
Hi!I have now updated my EfEntityStore so that it lets you Auto-register entitymappings and registers the Entitysets etc. You can check it out at: http://daniel.wertheim.se/2009/11/13/entity-framework-4-part-4-autoregister-entitymappings///Daniel