Design Meeting Notes - October 25, 2012
Change default mapping for DateTime
Currently Code First maps DateTime properties to the SQL datetime type. This is a problem because:
- DateTime is a value type, which means if no value is set for the DateTime property then the default value is used rather than null as would be the case for reference types
- The .NET default value for DateTime does not fit into a SQL datetime column
- This results in an exception that is not easy to interpret: “The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.”
- All of this happens just by creating a new object and trying to save it, and it’s not clear at all what the problem is.
The solution is to change the default mapping from datetime to datetime2. However, this is a breaking change because it changes the model that Code First generates, meaning that our model checking (using Migrations) will indicate that the model has been
changed even when the user didn’t make a change. This could result in runtime exceptions.
- Make the change and direct people to solutions for either migrating their databases or reverting the mapping using an attribute or the fluent API
- Do this, but allow older model builder versions to use the existing mapping. This is a bit tricky because it is provider-specific behavior.
- Do nothing and keep letting people know how to fix the issue. The workarounds are easy once the problem is understood. Bing finds solutions quite quickly.
- Consider improving the exception message, possibly by detecting the situation in the provider and throwing from there instead of letting the server throw.
- Need to be careful to only throw when really needed. For example, if server really has datetime2 even though SSDL has datetime, then we don’t want to throw. It’s pretty much impossible to know this.
We will leave the behavior as is. The breaking change and the confusion it will cause is not justified. Existing workarounds are reasonable and easy to find with a Bing search. Also, with lightweight conventions it should be easy to add a convention that
changes the mapping for all DateTime types if desired—we will use this as an example for lightweight conventions.
There are a couple of minor issues/questions with the lightweight conventions API:
1. It is possible to call Configure multiple times in one Add call. What should happen? Throw? Last wins? Likewise, it is possible to call Where without anything following it. Again, what should happen? Conclusion: change the API such that Where becomes
When and is always chained after configure. For example:
.Configure(config => config.Precision = 10)
.When(property => property.PropertyType == typeof(decimal))
With this pattern if multiple calls to Configure are placed in a single Add block it will act like calling Add multiple times. Also, When comes after Configure so there are no dangling Wheres.
2. Should it be possible to chain multiple calls to Add? Decision: no compelling argument either way, but for consistency and to make it easier to change in the future we will currently keep a void return and prevent chaining. One option for the future is
to return something that can then be used with Remove to remove the convention.
General note: the Code First configuration APIs should be consistent in this as much as possible.
DbConfiguration exploratory testing
Discussion of experience following DbConfiguration exploratory testing:
- EF does not use the default connection added by ASP.NET. This can be confusing. However, EF should use the connection if ASP.NET scaffolding is used—more testing to be done here. Also, the One EF tooling experience could configure the context to use the
ASP.NET connection if present. (http://entityframework.codeplex.com/workitem/624) We can’t really change EF to use the default connection
in the general case without it being an unacceptable breaking change.
- It is not always obvious that settings in the config file are overriding settings made in code-based configuration because making the connection between the XML and the code is not super-obvious.
- Could we only have the config file override the code-based if a “force” flag or similar is used? This is a bit ugly and would be a change to the current EF5 behavior.
- Should we stop manipulating the config file from NuGet and instead generate code-based configuration always? What about apps that already have existing config files? We will look into this as part of the other work being done on configless EF.
- We should definitely update the DbConfiguration documentation to make the connection between the code-based configuration and the config file clearer. (http://entityframework.codeplex.com/workitem/558)
- Filed bug “Any DbContext.Configuration change in DbInitializer persists for the first SaveChanges, but not the consecutive ones” (http://entityframework.codeplex.com/workitem/608)
- People don’t know what the provider manifest token is. Should we rename it? Problem is that it is part of the XML schema so we end up breaking/complicating the schema or we have two names for it. Most people don’t need to know what it is anyway, so may
be okay to leave as is.
- Provide additional documentation on what the DbConfiguration methods do. (http://entityframework.codeplex.com/workitem/374)
Code Contracts discussion
Investigation of using Code Contracts static analysis showed that it is possible to run static analysis after recent bug fixes. The results were:
- Took seven hours to complete and used 4GB memory
- Attempt to use static analysis caching caused crash
- Static analysis was able to make some assumptions about pre/post conditions to use for the analysis:
- 8000 suggested pre-conditions
- 23000 suggested post-conditions
- 27 possible errors—these will be investigated (http://entityframework.codeplex.com/workitem/625)
- There is not enough information in these suggestions to use them as a basis for creating more explicit conditions
What are the benefits/costs of continuing to use Code Contracts?
- We don’t use much more than simple pre-condition checking right now; we could do more, but it’s not a priority to do so so it seems unlikely that we will
- Static analysis is too slow/buggy to get much benefit
- One of the main reasons for using it was to avoid coding the manually adding the parameter name to simple null/string checks. We can now do this with the CallerXXX attributes instead.
- We could ship a contracts assembly, but we don’t currently and there doesn’t seem to be much demand for it.
- Contracts automatically compiles out internal stuff for release builds. This is nice, but we could live without it by leaving the internal checks intact or by conditionally compiling them.
- Build is slow because of the re-writing. We could try to make it faster by doing less or do on release builds only, but neither of these options are ideal.
- In general, we have run into several bugs (e.g. compiling out public surface contracts when it shouldn’t, creating unverifiable code, crashing on caching) that reduce the value proposition.
Conclusion: we will talk to the Contracts team and whether to use Code Contracts and if so how to get the best value from them.