次の方法で共有


Two specific ways to take more control of your object model

There was an interesting discussion on the LINQ Project General forum today (scroll down toward the end where we start talking about what the EF can and cannot do), and there were a couple of key points I wanted to capture since we've had so many discussions about persistence ignorance.  Two things which are requested fairly often when folks start to get serious about the object model they expose with their entities are:

  1. Making the default constructor private / forcing consumers to use factory methods.
  2. Creating read-only properties.

Neither of these happens by default with the code generated from the EF designer or from edmgen, but both are possible (even fairly straightforward) to do with the EF, so I want to make sure folks know about this.

Getting rid of the public parameterless constructor 
First off, it's important to realize that the EF does require that there be a parameterless constructor for each entity type (as described in this previous post).  This constructor is used by the system when materializing the results of queries.  This constructor does not, however, have to be public.  So if you want other consumers of your object model (such as an app developer--not the EF itself) to always use a constructor which takes a set of required parameters or to use a factory method, then you can just declare a private parameterless constructor in your partial class (or your own class directly if you are using IPOCO rather than the generated code).  This constructor can have business logic for initializing your entity if necessary, and it will be called when materializing objects from the database.  Consumers of your class will have to call some other public constructor or factory method you supply.

Another request which has been made, by the way, is that the mapping should make it possible to specify a constructor with parameters or a factory method which even the EF will use instead of the parameterless constructor.  This is something we will consider for future releases, but it won't be a part of the first release of the EF.

Creating read-only properties
This one is a bit harder because there's no straightforward way to do it with the automatically generated code.  If you are writing your own class, though, it's simple.  Just make the property which the EF persists private and then create a new public property with only a getter.  Unfortunately the EF will not allow you to attribute a field directly--it must be a property, and that property must (in the first version of the EF) have the exact same name as the corresponding property in your conceptual model, but there's nothing in the system which forces you to make that property public. 

So, if you want to try this out real quick, you can just take the output of codegen and change the property from public to private and then add a new property to your partial class which is public and has only a getter which access the private property (or the field directly).  The EF will use the getter and setter of the property which matches the conceptual model when materializing query results or reading data to write back to the database, but the consumers of your object model will only have access to your public property which can be read-only and/or have various additional business logic in it.

NOTE: I do not normally recommend editting the output of the code generator because if you ever need to regenerate your code these changes will be lost.  This is just a quick way to try out this capability of the EF.  If you need to make your persisted properties private, then you will need to switch to maintaining your own data classes either by taking a one-time snapshot of the output of codegen and then manually modifying the class from there on or outright writing your own IPOCO classes.

- Danny

Comments

  • Anonymous
    October 09, 2007
    PingBack from http://www.artofbam.com/wordpress/?p=6618

  • Anonymous
    October 19, 2007
    How about just adding the option to generate a protected setter?

  • Anonymous
    October 19, 2007
    This not a bad idea, but options for codegen, as it turns out, require a fair amount of infrastructure for us to handle in a coherent fashion.  Ideally this shouldn't be the case, but given all of the other competing things in v1 that's the situation we're in.  So for the first release this is something that will have to be handled another way. In future releases more flexibility around codegen in general is one of the many areas where I'd like to invest.

  • Danny
  • Anonymous
    October 20, 2007
    I'm glad I'm not building products if a simple change in the specs needs so much work ;) Jokes aside, time is precious this late in the project and should definatly be spent on building a lasting solution so I understand the situation your in and appriciate your efforts moving into V2. But one could at least wish :P