Code Only


There are currently two ways to get Entity Framework apps up and running, we call these Database First and Model First respectively.


Database First has been with us since .NET 3.5 SP1, and involves reverse engineering an Entity Data Model from an existing database.


Model First is new to Visual Studio 2010/.NET 4.0 and allows you to create an Entity Data Model from scratch and then generate a database and mapping for it.


However many developers view their Code as their model.


Ideally these developers just want to write some Domain classes and without ever touching a designer or a piece of XML be able to use those classes with the Entity Framework.
Basically they want to write ‘Code Only’.


We are pleased to announce that we’ll be shipping a preview of “Code Only” on top of the .NET Framework 4.0 Beta 1 (more on that in the coming days).


How it works:

To use Code only you simply write some POCO classes, here is a simple example:


public class Category
{
   public int ID { get; set; }
   public string Name { get; set; }
   public List<Product> Products { get; set; }
}


public class Product
{
   public int ID { get; set; }
   public string Name { get; set; }
   public Category Category { get; set; }
}


Then write a class that derives from ObjectContext that describes the shape of your model and how you want to access your POCO classes, so something like this:


public class MyContext : ObjectContext
{
   public MyContext(EntityConnection conn)
    : base(conn){ } 
   public ObjectSet<Category> Categories {
      get {
         return base.CreateObjectSet<Category>();
      }
   }
   public ObjectSet<Product> Products {
      get {
         return base.CreateObjectSet<Product>();
      }
   }
}


NOTE: this persistence / EF aware class could easily be in another assembly so you can keep it separate from your nice pristine domain classes.


At this point you have everything you need from a CLR perspective, but you won’t be able to use the MyContext class without some EF metadata, which is normally stored in the EDMX file.


But remember Code-Only means there isn’t an EDMX file.
So where do we get the metadata?
That is where the ContextBuilder class comes in:


SqlConnection connection = …; // some un-opened SqlConnection
MyContext context = ContextBuilder.Create<MyContext>(connection);


What is happening here is that the ContextBuilder is looking at the Properties on MyContext, inferring a default Conceptual Model, Storage Model and Mapping by convention, it the uses that metadata plus the SqlConnection you passed in to create an EntityConnection, and finally it constructs an instance of MyContext by passing the EntityConnection to the constructor we created previously.


Once you have an instance of your context, we ship several extension methods you can use to automatically create a database script, see if the database exists, drops the database, and/or create the database,. For example this code snippet uses two of those extension methods to create the database if it doesn’t already exist.


if (!context.DatabaseExists())
    context.CreateDatabase();


The CreateDatabase call looks at the EF metadata, in particular the Storage Model, aka SSDL, and uses it to produce Database Definition Language (or DDL) which it then executes against against the connection.


Overriding Conventions

In the examples so far everything is done by convention. This is great if you are happy with our conventions. However you may want to override them, for example to register different keys, use different mappings or use a different inheritance strategy etc.


To override the convention instead of creating an ObjectContext directly you create an instance of a ContextBuilder that you can configure.


var contextBuilder = new ContextBuilder<MyContext>();

In the first Feature CTP, Code Only provides the ability to override how the key properties are inferred:


contextBuilder.RegisterKey((Product p) => p.ID);


This code tells the builder that the key of Product is its ID property.


When you’ve finished configuring how you want your model and mappings to work in your code, you create an instance of your context, this time by calling Create on the builder instance you have been configuring:


MyContext context = contextBuilder.Create(connection);


It is that simple.


Over time the features of the ContextBuilder will grow so you will be able to setup custom mappings, mark properties as transient, setup up Facets (e.g. MaxLength), change inheritance strategies, link properties that are the inverse of each other together (e.g. product.Category and category.Products) and more. In fact here is an example of the sort of thing we are aiming to support for the next release of the Feature CTP:


builder[“dbo.prds”] = 
  from c in builder.OfType<Product>()
  select new {
    pcode = p.ID,
    p.Name,
    cat = p.Category.ID
  }
);


This snippet:



  • Maps Product entities to the ‘prds’ table.

  • Maps Product.ID to a ‘pcode’ column.

  • Maps Product.Name to a ‘Name’ column.

  • Maps the FK under the Product.Category relationship to the ‘cat’ column.

Here is another example that does basic TPH inheritance:


builder[“dbo.Cars”] = (
  from b in builder.OfTypeOnly<Car>()
  select new {
     id = b.CID.AsKey(),
     b.Color,
     b.Manufacturer,
     disc = “C”
   }
).Merge(
  from s in builder.OfType<SportsCar>()
  select new {
     id = s.CID.AsKey(), 
     s.Color, 
     s.Manufacturer, 
     disc = “S”, 
     hp = s.HorsePower, 
     tq = s.Torque
  }
);


These two examples just scratch the surface of what we are planning on doing, hopefully though they give you a sense of where we are heading.


We are super excited about Code Only. But as of right now our plans to support overriding conventions aren’t finalized, so we’d love to get your feedback, this really is your chance to help us get it right.


Alex James,
Program Manager, Entity Framework Team, Microsoft


This post is part of the transparent design exercise in the Entity Framework Team. To understand how it works and how your feedback will be used please look at this post.

Comments (32)

  1. Diego Vega says:

    It is always busy here with all the improvements we are doing in Entity Framework to make your code work

  2. lynn eriksen says:

    Wow! That’s stunning! You guy’s weren’t lying.

  3. Rik Hemsley says:

    What happens when the model changes? How does the database schema get updated?

  4. Thank you for submitting this cool story – Trackback from DotNetShoutout

  5. @Rik,

    We don’t yet have a good story for migrations.  The initial approach assumes that you are using the create database functionality during development and that you will recreate the database each time.  Obviously we would like to support scenarios where we can modify the database schema and preserve data, but we’re just not there yet in this release.  Working on it.

    – Danny

  6. Didier Georges says:

    What about the following approach -Code First- :

    1. create POCO classes (via VS or UML tools)

    2. generate EDMX -base- Model from (.cs) files

    3. keep those (.cs) files synced with model while adding specific persistance strategies via VS integrated EF designer…etc..

    Anyway : "Code Only" is "good news first". I’m waiting for it to pop-up ;-

  7. Daily tech links for .net and related technologies – June 11, 2009 Web Development Opinionated Input

  8. AlexJ says:

    @Didier,

    We have talked about Code-First too, but if we do it will come after Code-Only.

    As you can imagine with Code-Only internally the metadata required is being generated, so to do your (2) you just need a mechanism to get the metadata out of memory and on to disk. That should be relatively simple.

    Part (3) of your suggestion on the other hand is significantly harder because maintaining full fidelity in all transformations between code and model and model and code make things significantly harder.

    We are not sure that the payoff is sufficient, to deal with that extra complexity.

    I personally tend to think you get most of the benefits in a world where you do Code-Only, and then decide to go to emit your model / mapping / storage model, (aka EDMX) and use that from now on. I.e. going back from EDMX to the code based modeling and mapping wouldn’t be supported.

    – Alex

  9. Didier Georges says:

    @Alex,

    Yes, i agree with you about "is keeping the whole parts synced worth ?" though there will allways be some situation where people would to answer "yes".

    On the other hand, CodeFirst based on serializing (exporting to EDMX) what is produced "live" by CodeOnly will certainly be VERY usefull : many developpers generate source classes via  UML/MDA tools, maybe tomorrow via VS2010 architecture edition.

    When can we expect to be able to play with CodeOnly ?

    -Didier

  10. Rik Hemsley says:

    I wouldn’t expect EF to keep my DB and code models in sync. What I /would/ expect, however, is for it to provide a mechanism by which I can do this with my own code, i.e. some support for migrations.

    I don’t think I’ve ever worked on a project where the schema was completely fixed for the lifetime of the product, so it’s essential that alterations are possible without wiping out the database and re-entering the data.

    Of course it’s possible for us to dig into the database with SQL and migrate its structure ourselves, but this is error-prone if EF is supposed to be in control of the schema. The only way to be sure what EF would do is to actually create a new DB from the new schema via EF, then do a schema diff to find out what we need to change, then write the SQL…

  11. efdesign says:

    @Didier

    The first version (for Beta1) is coming soon, I don’t know exact dates, but you should think weeks rather than months.

    @Rik

    Yes Migrations are something that we keep hearing about again and again, and we agree they are important. While if might be hard to manually do migrations in the EDMX, I suspect it will be a lot easier with code only cause you can modify both ends (database and classes) and make them ‘meet’ in the middle with a minor change to your mapping configuration code.

    – Alex

  12. lynn eriksen says:

    Would it be correct to assume that TPT inheritance would work as well?

  13. AlexJ says:

    @Lynn

    Absolutely. We have worked through design validating that all three major inheritance strategies, TPH, TPT and TPC are supported.

    Alex

  14. Steve says:

    Is the ContextBuilder available in VS2010 beta1?

  15. efdesign says:

    @Steve

    No the context builder will ship soon in a Feature CTP that will extend Beta1. Watch out for an announcement soon on the adonet blog. i.e. http://blogs.msdn.com/adonet

    Alex

  16. perb says:

    Hi,

    it would be great if we could override conventions from the context also in the next CTP, that is the feature I really need as a framework developer. Please 😉

  17. @perb,

    Could you give a little more information?  When you say that you would like to override conventions from the context, do you mean that you want to change the mapping after the context has been created by calling methods on the context rather than on the context builder?  Or are you saying that you want to override conventions about the way the context is put together?  Or are you just saying you want the ability to override conventions?

    Our current plan is that in the next CTP you will be able to override all conventions when you setup the builder and then create a context that reflects a very fine-tuned mapping story, but you won’t be able to change the mapping for a particular context after it has been created.

    – Danny

  18. Jon says:

    It’s great to see that it will be possible to use model first instead of only database first in the next version of EF. This is a feature that I’ve wanted from the start. One other thing that I’m wondering though is, say I have a property of List<string> in my class. How will this be handled in EF? I’m using NHibernate now and it gets automatically binary serialized into a BLOB column. Does EF have support for this? I hope that support for this is included in EF.

  19. Jon says:

    One other thing that I just remember to ask, does it support ordered lists yet? I asked this awhile back and the answer was that you had to do it manually. What I want to do is do something like have a List<Person> or some other list and have it remember the ordering of the list. i.e. I should not have to manually add another property that holds the index value, it should do that for me automatically behind the scenes. This IMHO is a very important feature that was lacking before. Other ORMs have supported this for years. I really hope that this is included in the next version of EF. If it isn’t, that will be a real shame. The same thing goes for lists of primitives like List<string>. There should be a way to map properties to BLOBs and have them transparently serialize/deserialize. I want to switch from NHibernate, but, I’m not doing it until these features are implemented.

  20. @Jon,

    Sorry but neither lists of primitives nor ordered associations will be supported in EF4.  These are certainly features that can be added, and we’ll look to add them in a future release.  They are also things that can be layered on top of the EF without too much trouble in the meantime.

    – Danny

  21. Darren Kopp says:

    So i tried out this sample code, and quickly realized the only way the builder can build the set information is if the context has properties that return (I)ObjectSet<T>.

    What would be nice is to generate a generic context which just has methods such as Save<T>, Delete<T>, and Query<T> in which you interact with a set only via the CreateObjectSet<T> method.

    Will this be supported by EF4 RTM?

  22. perb says:

    @Daniel Simmons

    I would like to be able to create a context (using the context builder) for one or more POCO classes without having access to the POCO classes at compile time.

    My prefered approach would be to create the model (from my own metastore) using the context builder, then have callbacks on the created context whenever data from the actual classes has to be read/saved or mapped to the model for LINQ support.

    With this I can accomplish two goals:

    1) The callbacks would allow me to support properties that are stored in a dictionary on the class but still need to be mapped as ordinary columns. Very useful when building frameworks.

    2) I can provide a context that automatically maps to the database as defined in our store and the developer of our framework does not have to create their own context everytime. They just register their "type" in our store.

    So, more support for us framework developers that do not have access to the actual classes at compile time.

  23. Colin Meek says:

    @Darren

    The context builder also allows you to manually register a "root" entity type through the RegisterKey method. Calling RegisterKey tells code-only that a particular type hierarchy is interesting even absent an explicit IObjectSet<> property on the context class.

  24. Darren Kopp says:

    @Colin

    That must be forth coming. as of the feature ctp 1 having a context without IObjectSet and only using RegisterKey will throw an error on querying saying "Invalid object name ‘dbo.[TypeName]Set’."

  25. Scott C says:

    This may not be the place to ask, but will the next EF release support server generated keys/Identity columns when using a SQL Server Compact db?

  26. Niclas Pehrsson says:

    I see there are setters on Collections is there any way to make them private??

    And if I’m wanna go for real designing I maybe want to expose IEnumerable<Product> Products and have AddOrder(), RemoveOrder methods how can I achive that? I mean how can I set private fields like

    private IList<Product> _products;

    public IEnumerable<Product> Products

    {

        get { return _products; }

    }

    Instead of that not uses interfaces at all.

    public List<Product> Products { get; set; }

  27. Pete says:

    This is really great, and I think many of us like to work with objects in code rather than with database tables.  I have a couple of questions:

    1.  Will this work against SQL Azure?

    2.  Is it still possible to map some functions in the opposite direction?  For example, can a view or stored procedure be represented in the EF model even though we did model-first or code-first?  

  28. mjezzi says:

    seems like there's a bug when mapping foreign keys across tables in different schemas:  

    stackoverflow.com/…/entity-framework-ctp4-foreign-key-mappings-across-schemas-dont-work-properly

  29. VisionQuest says:

    Hi,

    I am new to EF and exploring to devlop business applications. My idea is to define a base entity and then all the other entities will be inherited from the base. So I will not have to define some common fields for each entity.  At the end I would be looking to implement a repository. But now I am just trying different approaches. These are my sample POCO

    [Serializable]

    public class BaseEntity

    {

    public virtual Guid Id { get; set; }

    public virtual Int32 HdVersionNo { get; set; }  

    public virtual Guid HdEditStamp { get; set; }

    }

    [Serializable]

    public class PaymentOrder : BaseEntity

    {

    public virtual decimal OrderNo { get; set; }

    public virtual byte OrderType { get; set; }

    public virtual decimal AccountNo { get; set; }

    }

    I am using following piece of code for mapping:

    var builder = new ModelBuilder();

    EntityConfiguration<T> config = new EntityConfiguration<T>();

    var model = builder.CreateModel();

    builder.Entity<T>();

    config.MapSingleType().ToTable(tableName);

    builder.Configurations.Add(config);

    builder.IncludeMetadataInDatabase = false;

    I get error 'Invalid column name 'Discriminator' as I try to return list of entities

    I searched and found people suggesting using "Descriminator' column. But in my case the base entity is not  a valid table at all and I do not have any descriminator column. Is there a way to avoid this error?

    Thanks in advance for any help on this

    VisionQuest

  30. Sam says:

    Any   launch date available for this "Code Only"?