Answered by:
Help Mapping EF Code First to an Existing Database

Question
-
Hello. First let me apologize for the lengthy post. I figured giving more details would help you understand the situation.
I’m trying to develop the data layer of my application using EF 5 Code First and mapping everything to an existing database. I’m wanting to use DbContext, POCOs, fluent table mappings, etc., but our existing database (the tables) isn’t straight-forward. So, I’m having trouble with a few things. I’ll try to briefly describe the situation now, then ask a couple questions later.
TablesAlarmDefinition AlarmDefinitionID int (primary key) (is identity) ... Alarm AlarmID int (primary key) (is identity) AlarmDefinitionID int (sort of a foreign key) (is nullable) SampleTagID int (is nullable) SampleTime DateTime (is nullable) ... ReasonAction Time DateTime (primary key) TagID int (primary key) ReasonActionID int (primary key) ReasonActionDefinition ReasonActionID int (primary key) (is identity) ...
So, one AlarmDefinition can have many Alarms. And, one ReasonActionDefinition can have many ReasonActions. There is an implicit relationship between Alarm and ReasonAction (i.e., one Alarm can have many ReasonActions). This is where I’m having the most troubles.
POCOs
AlarmDefinition public class AlarmDefinition { public int AlarmDefinitionID { get; set; } ... public virtual ICollection<Alarm> Alarms { get; set; } } Alarm public class Alarm { public int AlarmID { get; set; } public Nullable<int> SampleTagID { get; set; } public Nullable<System.DateTime> SampleTime { get; set; } ... public Nullable<int> AlarmDefinitionID { get; set; } public virtual AlarmDefinition AlarmDefinition { get; set; } // I don’t know if this is set up correctly public virtual ICollection<ReasonAction> ReasonActions { get; set; } } ReasonAction public class ReasonAction { public System.DateTime Time { get; set; } public int TagID { get; set; } public virtual Alarm Alarm { get; set; } public int ReasonActionID { get; set; } // Primary key public virtual ReasonActionDefinition ReasonActionDefinition { get; set; } } ReasonActionDefinition public class ReasonActionDefinition { public int ReasonActionID { get; set; } ... public virtual ICollection<ReasonAction> ReasonActions { get; set; } }
DbContext
public class AppDbContext : DbContext { public DbSet<Alarm> Alarms { get; set; } public DbSet<AlarmDefinition> AlarmDefinitions { get; set; } public DbSet<ReasonAction> ReasonActions { get; set; } public DbSet<ReasonActionDefinition> ReasonActionDefinitions { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new AlarmMap()); modelBuilder.Configurations.Add(new AlarmDefinitionMap()); modelBuilder.Configurations.Add(new ReasonActionMap()); modelBuilder.Configurations.Add(new ReasonActionDefinitionMap()); } }
Fluent Mappings
AlarmDefinitionMap public class AlarmDefinitionMap : EntityTypeConfiguration<AlarmDefinition> { public AlarmDefinitionMap() { this.HasKey(t => t.AlarmDefinitionID); ... this.ToTable("AlarmDefinition"); this.Property(t => t.AlarmDefinitionID).HasColumnName("AlarmDefinitionID"); ... } } AlarmMap public class AlarmMap : EntityTypeConfiguration<Alarm> { public AlarmMap() { this.HasKey(t => t.AlarmID); ... this.ToTable("Alarm"); this.Property(t => t.AlarmID).HasColumnName("AlarmID"); this.Property(t => t.AlarmDefinitionID).HasColumnName("AlarmDefinitionID"); this.Property(t => t.SampleTagID).HasColumnName("SampleTagID"); this.Property(t => t.SampleTime).HasColumnName("SampleTime"); ... this.HasOptional(t => t.AlarmDefinition) .WithMany(d => d.Alarms) .HasForeignKey(t => t.AlarmDefinitionID); } } ReasonActionMap public class ReasonActionMap : EntityTypeConfiguration<ReasonAction> { public ReasonActionMap() { this.HasKey(t => new { t.Time, t.TagID, t.ReasonActionID }); this.Property(t => t.TagID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); this.Property(t => t.ReasonActionID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); this.ToTable("ReasonAction"); this.Property(t => t.Time).HasColumnName("Time"); this.Property(t => t.TagID).HasColumnName("TagID"); this.Property(t => t.ReasonActionID).HasColumnName("ReasonActionID"); // Relationships // Not sure if this is correct since the related column names in the Alarm table are SampleTagId, not TagID and SampleTime, not Time. And SampleTagID and SampleTime in the Alarm table are not a primary keys. // There's an implicit one-to-many relationship between the Alarm and ReasonAction entities. this.HasRequired(t => t.Alarm) .WithMany(d => d.ReasonActions) .HasForeignKey(t => new { t.TagID, t.Time }); this.HasRequired(t => t.ReasonActionDefinition) .WithMany(d => d.ReasonActions) .HasForeignKey(t => t.ReasonActionID); } } ReasonActionDefinitionMap public class ReasonActionDefinitionMap : EntityTypeConfiguration<ReasonActionDefinition> { public ReasonActionDefinitionMap() { this.HasKey(t => t.ReasonActionID); ... this.ToTable("ReasonActionDefinition"); this.Property(t => t.ReasonActionID).HasColumnName("ReasonActionID"); ... } }
Whew! That was a lot of stuff. Anyway, here are some issues with our database and mapping things to EF: 1. No declarative referential integrity – all handled in triggers or legacy application code, 2. In the Alarm table, SampleTagID and SampleTime are not primary keys, yet these two columns are the one-side for an implicit one-to-many relation with the ReasonAction table, 3. Column names between the Alarms and ReasonAction tables do not match (SampleTagID and SampleTime for the Alarm table and Time and TagID for the ReasonAction table).
So, my questions are: A. Given the situation described above, can I make EF code first work with my existing database and tables?, B. How do I need to change my code to make the one-to-many relationship work between the Alarm and ReasonAction tables (so that when I query for Alarms the ReasonActions navigation property is populated with all related records)?, C. Any other suggestions?
Thanks!!!
Thursday, August 23, 2012 3:52 PM
Answers
-
If the database has exist and you want to use poco classes, you needn't to work with code first.
1. Using .net4.5 with database first, VS2012 will help you to create the poco classes.
2. Using VS2010 with database first, after creating models, using DbContext Generator to generate your poco classes.
Go go Doraemon!
- Proposed as answer by Doraemon_3 Tuesday, August 28, 2012 1:12 AM
- Marked as answer by Allen_MSDN Thursday, August 30, 2012 5:23 AM
Monday, August 27, 2012 9:13 AM
All replies
-
Hi,
Why don't you use model first directly? I am not clear about this line: 2. In the Alarm table, SampleTagID and SampleTime are not primary keys, yet these two columns are the one-side for an implicit one-to-many relation with the ReasonAction table,
Do you want to set SampleTagID and SampleTime in Alarm table as the primary keys?
Friday, August 24, 2012 9:31 AM -
If the database has exist and you want to use poco classes, you needn't to work with code first.
1. Using .net4.5 with database first, VS2012 will help you to create the poco classes.
2. Using VS2010 with database first, after creating models, using DbContext Generator to generate your poco classes.
Go go Doraemon!
- Proposed as answer by Doraemon_3 Tuesday, August 28, 2012 1:12 AM
- Marked as answer by Allen_MSDN Thursday, August 30, 2012 5:23 AM
Monday, August 27, 2012 9:13 AM