I thought I'd try the new DbContext way of doing things in EF 4.1, but ran into a problem.
I generate a new entity data model from database (SQL Server 2008) and then I use the DbContext generator.
When I try to fetch the table called Länder i get an exception.
var db = new MyEntities(); // instantiate DbContext subclass
var countries = db.Länder.ToList(); // boom
EntitySqlException: The simple identifier 'Länder' must contain basic Latin characters only. To use UNICODE characters, use an escaped identifier.
If if try other tables with latin names - all is fine. And I don't have this problem when using ObjectContext.
How am I supposed to escape the table name?
We (the EF team) investigated and found that we were not properly escaping (i.e. adding square brackets) for the names of the entity sets when we bootstrap the DbSets.
Thanks a lot for reporting this!
We are currently testing a fix that should be included in a future release. In the meanwhile, you should be able to workaround this by specifying the entity set name explicitly such that it doesn’t contain any characters that would need escaping.
When using Database First or Model First this can be done by editing the entity set names in the designer. When using Code First, it can be done by changing the name of the DbSet property:
public DbSet<Länder> Lander { get; set; }
or by overriding OnModelCreating in the context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Länder>().HasEntitySetName("Lander");
}
It looks like a bug in DbContext API because internally the query is converted to entity SQL which is parsed and if identifier contains national / unicode characters it must be escaped [Länder] but it is not. That is something you probably cannot control from your code.
I'm strongly against using non English names for identifiers (both code and database) so this is just another reason why it prove to be a wrong idea.
This bug is fixed in 4.3
http://blogs.msdn.com/b/adonet/archive/2012/01/12/ef-4-3-beta-1-released.aspx
Related
I am using the Entity Framework to generate data access code from an old database.
The database table names and properties are all named in capitals with _ to separate words ie. CLIENT, CLIENT_NAME, D_CLIENT_ID etc.
I have written a class to transform these into camel cased strings:
public static class Extensions{
public static string FirstCharToUpper(this string input)
{
return input.First().ToString().ToUpper() + input.Substring(1).ToLower();
}
public static string CamelCase(this string input)
{
return input.Split('_').Where(a=>!string.IsNullOrEmpty(a)).Select(a=>a.FirstCharToUpper()).Aggregate((a,b)=>a+b);
}
}
I am invoking this from my tt files and I have got to the point where my data classes and DbContext naming is the way I want it.
However I now get an error when I try to create a controller: 'Unable to retrieve metadata for myNamespace.Client'. Could not find the CLR type for 'myModel.ENTITYNAME'. (in capital)
To fix this, I made my Data.tt decorate my data classes with [Table("ENTITYNAME")] and my properties with [Column("COLUMNNAME")] - however this did not make any difference.
What am I missing?
Are you updating it the same way in all three (or two corresponding) layers: CSDL/MSL/SSDL? I would suspect there is a mismatch between two of the layers.
Possible useful in this case - here is a library I wrote for creating/updating/manipulating EDMX files a bunch of years ago: https://github.com/KristoferA/HuagatiEDMXTools/
If you use an older version of Visual Studio (2013 or older) then I also have a free VS addon/plugin that adds renaming and db<->model sync etc. You can download it from here:
https://huagati.com/edmxtools/
Update: based on the comments below, I think you are renaming classes and properties in the generated code without making the corresponding change in the CSDL.
Instead of changing the generated code / tt templates: change the names in the CSDL and the references to those CSDL objects in the MSL. Then the default templates will generate code with the class/property/etc names you want.
I really want to be able to use NodaTime in my Entity Framework Code First database projects but haven't found a "clean" way to do it. What I really want to do is this:
public class Photoshoot
{
public Guid PhotoshootId{get; set;}
public LocalDate ShootDate{get; set;} //ef ignores this property
}
Is there any supported or recommended approach to using NodaTime with EF Code First?
Until custom primitive type persistence is natively supported in Entity Framework, a common work around is to use buddy properties.
For each custom primitive within your domain model, you create an associated mapped primitive to hold the value in a format supported by Entity Framework. The custom primitive properties are then calculated from the value of their corresponding buddy property.
For example:
public class Photoshoot
{
// mapped
public Guid PhotoshootId{get; set;}
// mapped buddy property to ShootDate
public DateTime ShootDateValue { get; set; }
// non-mapped domain properties
public LocalDate ShootDate
{
get { // calculate from buddy property }
set { // set the buddy property }
}
}
We use NodaTime in our code first POCO's using exactly this approach.
Obviously this leaves you with a single type acting as both a code first POCO and a domain type. This can be improved at the expense of complexity by separating out the different responsibilities into two types and mapping between them. A half-way alternative is to push the domain properties into a subtype and make all mapped buddy properties protected. With a certain amount of wanging Entity Framework can be made to map to protected properties.
This rather splendid blog post evaluates Entity Framework support for various domain modelling constructs including encapsulated primitives. This is where I initially found the concept of buddy properties when setting up our POCO's:
http://lostechies.com/jimmybogard/2014/04/29/domain-modeling-with-entity-framework-scorecard/
A further blog post in that series discusses mapping to protected properties: http://lostechies.com/jimmybogard/2014/05/09/missing-ef-feature-workarounds-encapsulated-collections/
EF Core 2.1 has a new feature Value Conversions, which is exactly for this scenario.
//OnModelCreating
builder.Entity<MyEntity>
.Property(e => e.SomeInstant)
.HasConversion(v => v.ToDateTimeOffset(), v => Instant.FromDateTimeOffset(v));
.HasConversion has some other overloads to make this logic re-useable, for example you can define your own ValueConverter.
No "clean" way that I'm aware of because EF, as of this writing, doesn't have a mechanism for simple type conversion like you see in NHibernate (IUserType). A real limitation in EF as an ORM which causes me to change my domain to suit my ORM.
There is a provider specific way that works with Postgres (Npgsql).
Install the library
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime
And then while configuring DbContext, use this,
services.AddDbContext<PhotoshootDbContext>(opt =>opt.UseNpgsql(Configuration.GetConnectionString("ConnectionString"), o => o.UseNodaTime()));
There are some third party libraries for other providers too.
Say I have the following property in a class (where I'm using Code First):
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
I'd rather not decorate my Password property with these annotations. I'd rather use the Fluent Api if possible. How many of these annotations could be done using the Fluent Api? I know Required can be, and StringLength. But I don't know about ErrorMessage, DataType and Display.
I take the View:
a)Decorate the POCO with genuinely useful business constraints. MVC and EF amongst others will check a few of the important constraints for You.
b) You can and should add checking for custom Annotations or other business rules to the POCO.
see sample bloew if interested:
c) DB specific annotations belong in EF fluent API. If they are DB specific that dont belong on the POCO in my view. Eg Table name, schema, Foreign key, association maps, column renames and ignores etc.
d) Error messages and Display texts belong on the Model View.Or at least abstracted from teh POCO example below. I know people dont like double effort and will use POCO as Model views and like easy text and error message handling. But I prefer a full error message/text handling solution that is multi-lingual and configurable. Sticking texts on a POCO, isnt the best solution in my view.
Clearly style and build size influence the choice and many will disagree with d) and I dont have a big issue with that . Im taken a big picture design pattern view and look to separate and abstract where it makes sense.
here a little POCO extra sample, not with annotations but it could have been. I have seen some nice examples with annotations as well. This style of error can be used in MVC and is better than texts in annotations in my view.
public class POCODemo : IValidatableObject //various ways to trigger this. Some for free
/// poco members .... bla bla
//Support Business rules...
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var vResult = base.Validate(validationContext).ToList();
if (Poco.property1 || poco.property is nasty or xyz issue)//psuedo code for your check
var memberList = new List<string> { "PropertyName1" };
var err = new ValidationResult("Some Text comes from your TEXTPOOL of choice that explains the error", memberList);
vResult.Add(err);
// }
}
return vResult;
}
I know Required can be, and StringLength.
And that's all.
Keep in mind that the same attributes can be used by different "frameworks" and for very different purposes. If you use - for example - the Required attribute in a context of ASP.NET MVC it will be used for MVC model validation - on client side by some Javascript injected into the page or on server side to set ModelState.IsValid.
The Required attribute is also used by Entity Framework Code-First to validate an entity, but this has actually nothing to do with the MVC model validation. If you replace the Required attribute by configuration with Fluent API you still influence Entity Framework, but for ASP.NET MVC you just have removed the attribute, i.e. the property is not required anymore for MVC validation. ASP.NET MVC doesn't care about Entity Framework's Fluent API.
The same is true for StringLength. ErrorMessage, DataType and Display play no role with Entity Framework, neither as attributes nor are there counterparts in Fluent API.
For various reasons I would like to not store the connection string for my Entity Framework DB model in one of the various .config files. (I am using the latest and greatest DBContext API with the new Entity Framework version 4.1, .NET 4 and Visual Studio 2010 C#.) However, the code generation template for DBContext only creates a single parameterless constructor. (If I don't use the DBContext API, then my entity framework model has 7 different constructors to chose from, including the one I want.)
The only way I could figure out how to do this was to directly modify the code-generation template (context.tt file) to give me the constructor I want (example code below). This works, but it feels like I'm doing it "the hard way". What is the correct way to get a DBContext constructor that accepts a connection string?
public <#=Code.Escape(container)#>(string connectionString)
: base(connectionString)
{
<#
WriteLazyLoadingEnabled(container);
#>
}
One final note in case it might help somebody else. Although this method works, it took me a while to realize that the "connection string" is not strictly the DB connection string, but rather the special entity framework connection string which contains the DB connection string (just like what would be stored in the app.config file).
Your approach looks like the most correct way to do this. It's what the t4 templates were created for, and you're basically doing the same thing that the model-first templates do by default.
Another possibility would be to make the db context class be partial (if it isn't by default) and create another partial class file alongside it to add the constructor you want. But it seems likely that you'll want all of your t4-generated contexts to follow this pattern, so I think it's best to leverage the code generation to do this automatically the way you do in the question.
Is it possible to map a table column to a class field instead to a class property and how?
YOU CAN DO IT :)
Follow this link: http://weblogs.asp.net/ricardoperes/archive/2013/08/22/mapping-non-public-members-with-entity-framework-code-first.aspx
This is a common request, and really makes sense; we need to use LINQ expressions and a bit of reflection magic. First, an helper function for returning an expression that points to a member:
public static class ExpressionHelper
{
public static Expression<Func<TEntity, TResult>> GetMember<TEntity, TResult>(String memberName)
{
ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "p");
MemberExpression member = Expression.MakeMemberAccess(parameter, typeof(TEntity).GetMember(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Single());
Expression<Func<TEntity, TResult>> expression = Expression.Lambda<Func<TEntity, TResult>>(member, parameter);
return (expression);
}
}
Then, we call it on the DbContext.OnModelCreating method, as a parameter to StructuralTypeConfiguration.Property:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Project>().Property(ExpressionHelper.GetMember<Project, Decimal>("Budget")).IsRequired();
base.OnModelCreating(modelBuilder);
}
Entity Framework (Code First or not) does not support mapping to a field; only to properties.
UPDATE
As pointed out in the comments, these documents are a bit dated but might still help any beginner along:
Entity Framework Code first development Resources and Documentation
For the sake of completeness, heres a link to whats included in EF 4.1 RC: EF 4.1 Release Candidate Available
Changes since CTP5 (From the link above):
Rename of ‘DbDatabase’ to ‘Database’. This class has also moved
to the ‘System.Data.Entity’
namespace, along with the database
initializer classes.
Rename of ‘ModelBuilder’ to ‘DbModelBuilder’, to align with the
other core classes.
Validation in Model First and Database First. The new validation
feature was only supported in Code
First in CTP5. In RC the validation
feature will work with all three
development workflows (Model First,
Database First, and Code First).
Complete Intellisense docs. Feature CTPs were not extensively documented
because the API surface was changing
significantly between each release.
This release includes complete
documentation.
Removal of Code First Pluggable Conventions. Pluggable Conventions
were previewed in Feature CTP5 but
were not at go-live quality for this
release. This release still supports
the removal of default conventions.
Consolidation of IsIndependent in the Code First relationship API. When
configuring relationships in Feature
CTP5 the IsIndependent method was used
to identify that the relationship did
not have a foreign key property
exposed in the object model. This is
now done by calling the Map method.
HasForeignKey is still used for
relationships where the foreign key
property is exposed in the object
model.