Entity Framework 4.3 to Entity Framework 5 Mapping Exception - entity-framework

I'm in the process of migrating a project from Entity Framework 4.3 running on .net 4 to Entity Framework 5 running on .net 4.5. Without making any changes, when I try to run the project the code-first model configuration fails with a System.Data.MappingException with the message:
(495,10) : error 3034: Problem in mapping fragments starting at lines 495, 536:Two entities with different keys are mapped to the same row. Ensure these two mapping fragments do not map two groups of entities with different keys to the same group of rows.
[5 other similar paragraphs removed]
The message does not specify which entity or relationship is causing the problem and my model is reasonably complex. Is there any way that I can get some more helpful information to to make it easier to diagnose the problem?

Ladislav was correct to suggest an inheritance problem. It looks like Entity Framework 4.3 and Entity Framework 5 behave a little differently when it comes to code-first Table Per Hierarchy configurations.
In this case I had four derived types each with their own configuration class derived from EntityTypeConfiguration<T>. The base, abstract type did not have a configuration registered with the model builder. This was not a problem under EF 4.3 which simply created a table named after the base type with a 'Discriminator' column to distinguish between the types.
To get the same behaviour with EF 5 it was necessary to create an empty configuration class
public class MyBaseConfiguration : EntityTypeConfiguration<MyBase>
{
// Nothing happening here
}
and then register it with the model builder
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new MyBaseConfiguration());
// Add configurations for derived and other types as normal
}
}

Related

Why can't I use ApplyConfiguration() to add my audit log table (Audit.NET can't find it)?

I have an existing application that is built on Entity Framework Core 2.2.x. It is using modelBuilder.ApplyConfiguration() to associate entities with the data model dynamically. This works for all of the current entities and even my new AuditLog entity as far as the rest of the application is concerned.
However, when I configure Audit.NET's entity framework core provider to log into AuditLog, the data provider cannot write to the database:
The entity type 'AuditLog' was not found. Ensure that the entity type has been added to the model.
I have scoured the internet for solutions to that error, and found that adding this line to my code will cause Audit.NET to find my AuditLog:
modelBuilder.Entity<AuditLog>().ToTable("AuditLog", "Audit");
My code:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
Type[] maps = EntityFrameworkReflectionMapping.Get(EntityTypeConfiguration(), BoundAssemblies);
foreach (object instance in maps.Select(Activator.CreateInstance))
modelBuilder.ApplyConfiguration((dynamic)instance);
modelBuilder.Entity<AuditLog>().ToTable("AuditLog", "Audit");
base.OnModelCreating(modelBuilder);
}
Why do I need to add the entity explicitly, when the rest of the system works as-is?
Additionally, the changes are being detected by Audit.NET through entities which are not explicitly added. So the problem seems to be with Audit.NET's entity framework data provider, or how I'm using it.
I would expect that the data provider would respect the modelBuilder.ApplyConfiguration() approach to associating entities.
There are many things that could be causing the exception, but looks like EF is not being able to detect the entity-table relation for your AuditLog.
Look for a wrong connection string, maybe your AuditLog being defined on a different assembly than other entities.
Also try adding the AuditLog entity class within a db set as a property on your DbContext, for example:
public class MyContext : AuditDbContext
{
//...
public DbSet<ModelName> ModelName { get; set; }
}

cant add migration to ef 7

I am still in the process of porting my old MVC project to the latest asp.net 5 MVC and EntityFramework 7. To accomplish this I first reverse engineered an existing database from the old project using the ef commands. That created all of my model classes correctly (or mostly so). I have manually edited the code to get through all of the initial errors. I have that compiling with almost no additional code from the original project. In other words I only have the model classes, and the DbContext class so far in the solution. All of this is in an assembly and I have no migrations at all in the codebase, just the Migrations directory. What I thought would make sense is to add a migration to baseline the database from what was reverse engineered. I should mention that my DbContext inherits from IdentityDbContext
public partial class STOrmContext : IdentityDbContext<ApplicationUser>
{
}
My project is split into two components. All database and models in an assembly, and MVC stuff in a separate project.
when I type
dnx ef command migrations add Initial
I get the following error message
The entity type 'Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin<string>' requires a key to be defined.
I guess I just don't really understand how to bootstrap a legacy database into EntintyFramework 7. Can someone point me in the right direction.
I found the answer myself.
It turns out it was a couple of things I was not addressing.
When I reverse engineered the old database it created models for the
identity stuff from the legacy application.
I deleted those.
I also needed to call the base OnModelCreating() so that it could configure
Identity stuff.
protected override void OnModelCreating(ModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
}
I guess I should have paid more attention to what was really happening before jumping to a question on StackOverflow

Map Read from CRUD in EF 6 Fluent API

I've been scouring the net, but haven't found anything useful. I have a POCO class that I want to wire up to a stored procedure in Entity Framework 6.x. I've see how to do it in the Fluent API for Inserts, Updates, and Deletes.... but not for just straight Reading.
I found this: EF 6 Code First Stored Procedure - Read Only, but it looks like it's just a method on some controller somewhere.
Is there a way where I can call the context like I would any other Entity. I.E.,
ctx.Products.Where( p => p.ProductId == productId )?
I would approach this is one of two ways.
Domain / POCO mapping
If the underlying issue is a mismatch between your Entity Framework model POCO's and your (presumably purely logical) domain, I would match the EF model directly to the database schema and them map them across to domain types accordingly. I.e have a separate domain model to your EF poco's. The mapping work previously done by your proc would then be done within the domain mapper.
Abstract DbContext usage behind Repositories
Rather than having consumers directly query the context, you could abstract the context behind entity repositories and map between a SqlQuery calling a proc and your POCO's in the repository methods
E.g. here is some rough code:
public class MyEntityRepository()
{
public ICollection<MyEntity> GetAll()
{
return _myContext.SqlQuery<MyEntity>("exec myProc", params);
}
}
Neither of these options would be quick to implement and introduce into your codebase though.

Entity Framework 5.x data annotations

I was using EF 4.x database-first approach. I have the edmx file and it generated the C# class that derived from EntityObject. I have an ASP.NET MVC 4 application that uses the generated class as model. The client validation that validates the required fields worked fine.
Now I moved to EF 5 and used the DbContext generator, it generates the POCO C# class. I found that the required field validation no longer works in EF 5.
I think the problem is that in EF 4.x EntityObject generator, the generated class has [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)] attribute. However in the EF 5.x POCO class, no data annotation attributes are generated. So the required field information is lost.
So my questions are:
Why does the EF 5.x DbContext generator not generate
[Required] annotations from the edmx file?
Where is the right place to
put these data annotations? Should I modify the .tt file to generate
the [Required] attribute? Or manually write a [MetadataType] partial
class and define data annotation attributes in a separate
class?
1) I don't know why. I just know that Db-first approach doesn't add any data annotations to properties.
2) Indeed creating a separate partial class! Here is an example. Because EF will overwrite and regenerate all POCO classes every time you update your model, any changes (also data annotations) to those classes will be lost...
Perhaps you can find this link useful.
EF Validation
Simply add Metadata class with the required validation:
[MetadataType(typeof(UserMetadata))
public partial class User
{
...
}
public class UserMetadata
{
[UserValidate("State")]
public string State;
// etc.
}
hope this can help

Get DbContext for Entities

Okay, I feel a bit foolish for having to ask this but I guess my understanding of the inner workings of Entity Framework is lacking.
I'd like to experiment with work with DbContext. I have an existing ASP.NET MVC application using EF 4.2. I can get my entities using:
var context = new MyEntities();
And this works just fine.
But how the heck to I get the same data represented by a DbContext?
So I guess you are using default code generator provided by EDMX designer - it will use ObjectContext and heavy weight EntityObject based entities.
If you want to use DbContext you must:
Turn off that default code generation - in property window remove Custom Tool for EDMX file
Download and install DbContext T4 generator (you can get it directly from extension manager in Visual Studio)
In EF designer select Add Code Generation Item from context menu in the designer surface (not on entity)
Now EF will add two .tt files to your project - one will be responsible for creating a new class for every entity or complex type defined in your EDMX file and the second will be responsible for creating class derived from DbContext and exposing sets for all your entity types