Entity Framework and Data binding - entity-framework

I have two tables that are built using codefirst entity framework.
public class TimeEntry:Entity
{
[Required]
[Display(Name = "Activity")]
public int ActivityId { get; set; }
public virtual Activity Activity { get; set; }
}
public class Activity:Entity
{
private ICollection<TimeEntry> _timeEntries;
[Required]
public string Description { get; set; }
public virtual ICollection<TimeEntry> TimeEntries
{
get
{
return _timeEntries ?? (_timeEntries = new List<TimeEntry>());
}
set
{
_timeEntries = value;
}
}
}
public class Entity
{
public int Id { get; set; }
}
These are the classes I have created for my Db. There is no problem with creating the database. When I try to perform CRUD operations I get the error
DataBinding: 'System.Data.Entity.DynamicProxies.Activity_AD12BF558F098271F1F51B3B1489B4B3B281FD0B686C8457333DE5BEE0E8B6A9' does not contain a property with the name 'ActivityId'
It is trying to find ActivityId in the Activity table however the primary key is Id. How do I map the foreign key ActivityId in the TimeEntry table to the primary key Id in the Activity table.

You can use fluent api to let EF know about you mappings.
public class ActivityMap : EntityTypeConfiguration<Activity>
{
public ActivityMap()
{
this.HasKey(a => a.Id);
}
}
public class TimeEntryMap : EntityTypeConfiguration<TimeEntry>
{
public TimeEntryMap()
{
this.HasKey(t => t.Id);
// Relationships
this.HasRequired(t => t.Activity)
.WithMany(t => t.TimeEntries)
} .HasForeignKey(d => d.ActivityId);
}
Then in your context:
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ActivityMap());
modelBuilder.Configurations.Add(new TimeEntryMap());
}
}
I think this will solve your issue.
Also, (as a side note) instead of defining _timeEntries, you can use auto implemented property for TimeEntries and initialize it in you ctor. like below:
public class Activity:Entity
{
public virtual ICollection<TimeEntry> TimeEntries { get; set; }
public Activity()
{
this.TimeEntries = new List<TimeEntry>();
}
}

hi i have the same problem
If one specifies DataKeyNames property as ID and the actual column name is CustomerID. It will throw the above error.
If one specifies DataTextField or DataValueField property as ID and the actual column name is CustomerID. It will throw the above error.
and found the answer here it work for me link

If you are using Code First, you need to indicate the mapping of ActivityId => Id by overriding OnModelCreating in your DbContext.
At a suggestion, it seems you are mixing the concerns of DTO and MVC ViewModel in the same entity. Why not separate these concerns into 2 different entities?

Related

How can I define a 1:0 relationship using Entity Framework Core 2.1? [duplicate]

This question already has an answer here:
One-to-Zero relationship with Entity Framework Core 2.0
(1 answer)
Closed 4 years ago.
Updating entity Persons I get the following error:
System.InvalidOperationException: The property 'ID' on entity type 'Person' has a temporary value. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.
at Microsoft.EntityFrameworkCore....
This has been discussed several places, and a similar issue was reported fixed by the EF Core team. However, one of those posts is about multiple updates to an entity and the one-to-many solution does not work here; additionally, I cannot make one ID column nullable and prefer to use the fluent API configuration. The documentation example does not work either, so I am asking here.
The scenario is that I am upgrading a legacy ASP.NET MVC 4 project to ASP.NET MVC Core, and as a result I am upgrading from EF 6.1 to EF Core 2.1. I will happily move to 2.2 instead if it solves this problem; I think it was still in prerelease when I started.
Here is a (ridiculously) simplified version of my entities:
public class Person
{
public int ID { get; set; }
public string name { get; set; }
public virtual Worker Worker { get; set; }
}
public class Worker
{
public int ID { get; set; }
public string somePersonalDetails { get; set; }
public virtual Person Person { get; set; }
// other relationships exist
}
I am using fluent API configuration:
public class PersonBuilder
{
public PersonBuilder(EntityTypeBuilder<Person> entity)
{
entity.HasKey(k => k.ID);
entity.HasOne(p => p.Worker)
.WithOne(p => p.Person)
.HasForeignKey<Person>(p => p.ID)
//.IsRequired(false) //?
.OnDelete(DeleteBehavior.Cascade);
}
}
public class WorkerBuilder
{
public WorkerBuilder(EntityTypeBuilder<Worker> entity)
{
entity.HasKey(k => k.ID);
// other relationships are defined
}
}
public override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Configurations<Person>().Add(typeof(PersonBuilder));
builder.Configurations<Worker>().Add(typeof(WorkerBuilder));
}
The reason that it's split apart like that is because I adapted it from our leftover EF 4/5/6 configuration. Yay legacy code. Nevertheless it works (for other defined types). The way I am reading that, it says "define a foreign key on the related Worker object pointing to the ID of this object." It does just the opposite.
I have tried:
Defining the key relationship on the WorkerBuilder type instead. This yields SQLite Error 19: 'FOREIGN KEY constraint failed'. Amazingly, however, it still attempts to define the key on the Person entity, which is wrong.
Removing some of the specific expressions in hopes that EF will just figure out the relationship itself. It doesn't; if I provide too little information, it tries to use columns|fields that don't exist (e.g., "PersonID", or is unable to figure out the relationship altogether.
So, I am stumped. Has anyone done this successfully? In plain English,
"A person may or may not have a worker record" (1:0); and,
"if they have a worker record, both records have the same ID." (FK_W_ID__P_ID)
Write your model classes as follows:
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public virtual Worker Worker { get; set; }
}
public class Worker
{
public int PersonId { get; set; }
public string somePersonalDetails { get; set; }
public virtual Person Person { get; set; }
// other relationships exist
}
Then in the PersonConfiguration and WorkerConfiguration:
public class PersonConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.HasKey(u => u.PersonId);
}
}
public class WorkerConfiguration : IEntityTypeConfiguration<Worker>
{
public void Configure(EntityTypeBuilder<Worker> builder)
{
builder.HasKey(u => u.PersonId);
builder.HasOne(u => u.Person)
.WithOne(b => b.Worker)
.HasForeignKey<Worker>(b => b.PersonId);
}
}
Then in the OnModelCreating of DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new PersonConfiguration());
modelBuilder.ApplyConfiguration(new WorkerConfiguration());
}

Manually map 1 to Many Relationship

I am trying to map an existing database in EF with code first. The provider (jetEntityFrameworkProvider) does not support DB first.
I am trying to map the Table "Component" (1) to the Table "ComponentText" (Many)
This is what I have
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Component>().Map(m =>
{
m.Properties(p => new { p.ComponentText });
m.ToTable("ComponentText");
});
modelBuilder.Entity<ComponentText>().HasKey(t => t.ComponentCounter);
}
When I run it I get the follow error
System.InvalidOperationException: 'The property 'ComponentText' on type 'Component' cannot be mapped because it has been explicitly excluded from the model or it is of a type not supported by the DbModelBuilderVersion being used.'
These are my models with only the relevant properties
Component
[Table("Component")]
public class Component
{
[Key]
[Column("Counter")]
public int Id { get; set; }
[Column("Name")]
public virtual ICollection<ComponentText> ComponentText { get; set; }
}
ComponentText
[Table("ComponentText")]
public class ComponentText
{
[Key]
[Column("Counter")]
public int Id { get; set; }
public int TextId { get; set; }
public string Text { get; set; }
//** Foreign Key
public int ComponentCounter { get; set; }
}
ETA:
I've changed my code per Backs answer. However, it is still not working. I have tried several variations. .HasRequired(), .HasOptional().
Note I removed m.ToTable("ComponentText"); As Component is already mapped in the class to the "Component" Table.
I am getting 0 results and receiving this error in Results View
Error = The function evaluation requires all threads to run.
If I uncomment the section line in the comment modelBuilder.Entity<ComponentText>().HasKey(t => t.ComponentCounter);
I get this error
Component_ComponentText_Target: : Multiplicity is not valid in Role 'Component_ComponentText_Target' in relationship 'Component_ComponentText'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.
public class ProjectContext : DbContext
{
private DbConnection con = new JetConnection();
public ProjectContext() : base(new JetConnection(#"Provider=Microsoft.Jet.OLEDB.4.0; Data Source = 'C:\Users\Ben-Laptop\Desktop\Test-Project.sep'; User Id = Admin; Jet OLEDB:Database Password = SEEME;"), true)
{
Database.SetInitializer<ProjectContext>(null);
}
public DbSet<Component> Components { get; set; }
public DbSet<Content> Contents { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Component>().HasMany(p => p.ComponentText).WithOptional().HasForeignKey(p => p.ComponentCounter);
//modelBuilder.Entity<ComponentText>().HasKey(t => t.ComponentCounter);
}
}
Remove m.Properties(p => new { p.ComponentText }); because it only maps property ComponentText
Add mapping for collection
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Component>().Map(m =>
{
m.ToTable("ComponentText");
})
.HasMany(p => p.ComponentText)
.WithRequired()
.HasForeignKey(p => p.ComponentCounter);
}
Entity Framework Fluent API - Relationships

Map Existing Entity with Existing Table in Entity FrameWork

Is it possible to map existing tables with existing Entities in Entity frame work as like NHibernate doing.
For example. I have entity as
public class User
{
public Int64 userId { set; get; }
public String Username { set; get; }
public Int64 RoleId { set; get; }
}
public class Role
{
public Int64 roleId { set; get; }
public String roleName { set; get; }
public IList<User> listUser { set; get; }
}
I have Table as
Users with id,name,roleId
Roles with id,name.
Now I want to map both using XML files. Is it possible to map exiting tables with exiting Entities.
You have a few options:
1) Manage your mapping via the database first edmx file (see http://www.asp.net/mvc/tutorials/mvc-5/database-first-development/creating-the-web-application)
2) Start with the database first approach then move over to a code first like approach using the fluent api (see http://agilenet.wordpress.com/2011/04/11/entity-framework-4-1-rc-with-an-existing-database/)
Usual way of mapping in EF is data annotation attributes or fluent mapping (actually with NHibernate fluent mapping is also better, because it gives you compile-time checks). So, here is fluent mapping for your classes:
public class UserMapping : EntityTypeConfiguration<User>
{
public UserMapping()
{
ToTable("Users"); // Not necessary, EF will use this mapping by default
HasKey(u => u.userId);
Property(u => u.userId).HasColumnName("id");
Property(u => u.Username).HasColumnName("name");
Property(u => u.RoleId).HasColumnName("roleId");
}
}
public class RoleMapping : EntityTypeConfiguration<Role>
{
public RoleMapping()
{
ToTable("Roles"); // Not necessary, EF will use this mapping by default
HasKey(r => r.roleId);
Property(r => r.roleId).HasColumnName("id");
Property(r => r.roleName).HasColumnName("name");
HasMany(r => r.listUser)
.WithRequired()
.HasForeignKey(u => u.RoleId);
}
}
Just provide these mappings to your DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserMapping());
modelBuilder.Configurations.Add(new RoleMapping());
base.OnModelCreating(modelBuilder);
}
I suggest you to read MSDN article Configuring/Mapping Properties and Types with the Fluent API.
Side note - another article to read is Naming Guidelines, especially its Capitalization Styles part.

How to have an entity inherit from another base entity and map to db using TPC with EF 4.2?

Say I have an entity model aggregate for Activity, like so:
public class Activity : Entity
{
public int PersonId { get; set; }
public virtual Person Person { get; set; }
public int Number { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public virtual ICollection<ActivityTag> Tags { get; set; }
}
public class ActivityTag : Entity
{
public int ActivityPersonId { get; set; }
public int ActivityNumber { get; set; }
public virtual Activity Activity { get; set; }
public int Number { get; set; }
public string Text { get; set; }
}
Forget about the relation between Activity and Person, but note the 1..* relation between Activity and ActivityTag. The fluent mapping looks more or less like this:
public class ActivityOrm : EntityTypeConfiguration<Activity>
{
public ActivityOrm()
{
ToTable("Activity", "Activities");
HasKey(p => new { p.PersonId, p.Number });
HasRequired(d => d.Person)
.WithMany()
.HasForeignKey(d => d.PersonId)
.WillCascadeOnDelete(true);
HasMany(p => p.Tags)
.WithRequired(d => d.Activity)
.HasForeignKey(d => new { d.ActivityPersonId, d.ActivityNumber })
.WillCascadeOnDelete(true);
Property(p => p.Content).HasColumnType("ntext");
}
}
public class ActivityTagOrm : EntityTypeConfiguration<ActivityTag>
{
public ActivityTagOrm()
{
ToTable("ActivityTag", "Activities");
HasKey(p => new { p.ActivityPersonId, p.ActivityNumber, p.Number });
Property(p => p.Text).IsRequired().HasMaxLength(500);
}
}
Given this, I want to introduce a new collection property to the Activity entity:
public ICollection<DraftedTag> DraftedTags { get; set; }
The DraftedTag entity should have the same exact properties and primary key as ActivityTag. The only thing that should be different is the table it is mapped to. I tried creating a class that derived from ActivityTag, like so:
public class DraftedTag : ActivityTag
{
}
public class DraftedTagOrm : EntityTypeConfiguration<DraftedTag>
{
public DraftedTagOrm()
{
Map(m =>
{
m.MapInheritedProperties();
m.ToTable("DraftedTag", "Activities");
});
HasKey(p => new { p.ActivityPersonId, p.ActivityNumber, p.Number });
}
}
The DraftedTagOrm has been added to the modelBuilder.Configurations collection, but without even adding the foreign key association to Activity, I get the following exception:
The property 'ActivityPersonId' is not a declared property on type
'DraftedTag'. Verify that the property has not been explicitly
excluded from the model by using the Ignore method or
NotMappedAttribute data annotation. Make sure that it is a valid
primitive property.
When I completely duplicate the code from the ActivityTag class and the ActivityTagOrm constructor into the respective DraftTag class / configuration constructor, then it works as expected -- I get two different tables with identical schemas, but different names. However each time I want to make a change to the ActivityTag class, I must make a corresponding change in the DraftTag class.
Is it possible to make this code DRYer by having DraftTag extend ActivityTag? If so, what would the EntityTypeConfiguration look like for DraftTag?

EF4 CTP5, mapping different entities to the same (existing) table

By code-first approach (but with an existing db schema), we are trying to map 2 different entities (Customer and Resource) to the same table. Both entities has the same keys and mapping.
However, when running the app, we have a runtime error telling us that mysterious message:
System.InvalidOperationException: Type 'Resource' cannot be mapped to table 'CLIENT' since type 'Customer' also maps to the same table and their primary key names don't match. Change either of the primary key property names so that they match.
Example:
public class EntityA
{
public string ID { get; set; }
public string Discriminator { get; set; }
public string TimeStamp { get; set; }
}
public class EntityB
{
public string ID { get; set; }
public string Discriminator { get; set; }
public string CreatedBy { get; set; }
}
public class EntityAConfiguration : EntityTypeConfiguration<EntityA>
{
public EntityAConfiguration()
{
HasKey(x => new {x.ID, x.Discriminator } );
Property(x => x.ID).HasColumnName("MyTable_ID").HasDatabaseGenerationOption(DatabaseGenerationOption.None);
Property(x => x.Discriminator).HasColumnName("MyTable_Discriminator").HasDatabaseGenerationOption(DatabaseGenerationOption.None);
Property(x => x.TimeStamp).HasColumnName("MyTable_TimeStamp");
ToTable("MyTable");
}
}
public class EntityBConfiguration : EntityTypeConfiguration<EntityB>
{
public EntityBConfiguration()
{
HasKey(x => new { x.ID, x.Discriminator });
Property(x => x.ID).HasColumnName("MyTable_ID").HasDatabaseGenerationOption(DatabaseGenerationOption.None);
Property(x => x.Discriminator).HasColumnName("MyTable_Discriminator").HasDatabaseGenerationOption(DatabaseGenerationOption.None);
Property(x => x.CreatedBy).HasColumnName("MyTable_CreatedBy");
ToTable("MyTable");
}
}
The above code is similar to our Customer/Resource code (but simpler for the explanation!).
However, get get the same Error message, telling us that EntityA and EntityB cannot be mapped to the same table because their primary key names don't match.
Any idea of what is wrong with our mapping?
Any idea how we could different entities to the same table?
Thanks for your help
Mapping 2 entity to one table requires that you create a Complex Type or Table Per Hierarchy (TPH). You can't just map 2 entities to one table like this. Let me know which one is better describe your domain model and I will provide you with the required object model/fluent API code.
Update: TPH Mapping:
public abstract class EntityBase
{
[Column(Name = "MyTable_ID")]
public string ID { get; set; }
[Column(Name = "MyTable_Discriminator")]
public string Discriminator { get; set; }
}
public class EntityA : EntityBase
{
[Column(Name = "MyTable_TimeStamp")]
public string TimeStamp { get; set; }
}
public class EntityB : EntityBase
{
[Column(Name = "MyTable_CreatedBy")]
public string CreatedBy { get; set; }
}
public class StackoverflowTestContext : DbContext
{
public DbSet<EntityBase> Entities { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EntityBase>()
.HasKey(x => new { x.ID, x.Discriminator });
modelBuilder.Entity<EntityBase>()
.Map<EntityA>(m => m.Requires("TPHDiscriminator")
.HasValue("yourDesiredValueForA"))
.Map<EntityB>(m => m.Requires("TPHDiscriminator")
.HasValue("yourDesiredValueForB"))
.ToTable("MyTable");
}
}