Configure a one directional relationship in entity framework - entity-framework

I have a Model
HUBS -< SECTIONS
sections are a tree hierarchy but they all belong to a hub (there is another table managing the hierarchy as one section can appear twice in the tree)
A hub should also have a root section, so on my hub entity I have:
public partial class Hub
{
public Hub()
{
this.Sections = new List<Section>();
}
public int HubId { get; set; }
public string Name { get; set; }
public virtual ICollection<Section> Sections { get; set; }
public int RootSectionId { get; set; }
public virtual Section RootSection { get; set; }
}
If I don't set an mapping as per:
public class HubMap : EntityTypeConfiguration<Hub>
{
public HubMap()
{
// Primary Key
this.HasKey(t => t.HubId);
// Table & Column Mappings
this.ToTable("Hubs");
this.Property(t => t.HubId).HasColumnName("HubId");
this.Property(t => t.Name).HasColumnName("Name");
// Relationships
this.HasRequired(t => t.Site)
.WithMany(t => t.Hubs)
.HasForeignKey(d => d.SiteId);
}
}
I get an error about not finding RootSection_SectionId column. Now I could just rename the column to match, but in the interests of my understanding of EF mapping, I'd like to be able to specify they column, which is "RootSectionId"
What would I need to include in the mapping file to map this field?

Something like :
this.HasRequired(t => t.RootSection)
.WithMany()
.HasForeignKey(d => d.RootSectionId);

Related

How to create relationship with temporal table in EF Core

I want to create a 1-0..1 relation between a table and a temporal table using EF Core code-first approach. But when I add the migration I get the error :
Navigation 'Ticket (Dictionary<string, object>).TicketAdministration' was not found. Please add the navigation to the entity type before configuring it.
I let you see step by step what I am doing:
I create the Ticket and TicketAdministration classes:
public partial class Ticket
{
public long Id { get; set; }
//... other unuseful props
public virtual TicketAdministration TicketAdministration { get; set; }
}
public class TicketAdministration
{
public long Id { get; set; }
//... other unuseful props
public long? TicketId { get; set; }
public virtual Ticket Ticket { get; set; }
}
Then I configured the two classes/tables:
modelBuilder.Entity<Ticket>(entity =>
{
entity.ToTable("tickets");
entity.Property(e => e.Id)
.HasColumnType("bigint")
.ValueGeneratedOnAdd();
});
modelBuilder.Entity<TicketAdministration>(entity =>
{
entity.ToTable("ticket_admininistration", "admin", t => t.IsTemporal());
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).UseIdentityColumn(1, 1);
entity.HasOne(d => d.Ticket)
.WithOne(p => p.TicketAdministration)
.HasForeignKey<TicketAdministration>(b => b.TicketId)
.OnDelete(DeleteBehavior.ClientCascade)
.HasConstraintName("FK_dbo.Tickets_admin.TicketAdministration_TicketId");
});
How do I have to configure the relationship? Why is it expecting a dictionary? What the dictionary represent?
Thank you

BUG: Entity Framework Power Tools Fails to Generate Designer

Entity Framework 6.1 using Power Tools 4 generates an error when using the command:
View Entity Data Model (Read Only) on the context.
The error:
An error occurred while trying to build the model for Context. See the output window for details.
The output window basically states:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMethodException: Method not found: 'xyz.domain.User xyz.domain.DomainBase.get_ModifiedBy()'
* CRITICAL * The power tools are also caching the schema and do NOT update with changes! ***
Example:
Create a base class:
public abstract class DomainBase {
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
public User CreatedBy { get; set; }
public string CreatedByName { get; set; }
public User ModifiedBy { get; set; }
public string ModifiedByName { get; set; }
}
Create a class that inherits from the base class:
public class User : DomainBase {
public int UserId { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public string Salt { get; set; }
public string Pin { get; set; }
}
Create Base Mapping:
public class DomainBaseConfig<TEntity> : EntityTypeConfiguration<TEntity>
where TEntity : DomainBase {
public DomainBaseConfig() {
this.HasOptional(c => c.ModifiedBy).WithOptionalDependent()
.Map(m => m.MapKey("ModifiedById"));
this.HasOptional(c => c.CreatedBy).WithOptionalDependent()
.Map(m => m.MapKey("CreatedById"));
this.Property(t => t.CreatedByName).HasMaxLength(FieldMaxSize.FullName).IsRequired();
this.Property(t => t.ModifiedByName).HasMaxLength(FieldMaxSize.FullName).IsRequired();
this.Property(t => t.DateCreated).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
this.Property(t => t.DateModified).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
}
}
Created User class mapping:
public UserConfig() {
this.ToTable("Users");
this.HasKey(c => c.UserId);
this.Property(t => t.FirstName).HasMaxLength(FieldMaxSize.FirstName).IsRequired();
this.Property(t => t.LastName).HasMaxLength(FieldMaxSize.LastName).IsRequired();
this.Property(t => t.Password).HasMaxLength(FieldMaxSize.Password).IsRequired();
this.Property(t => t.Pin).HasMaxLength(FieldMaxSize.Pin).IsRequired();
this.Property(t => t.Salt).HasMaxLength(FieldMaxSize.Salt).IsRequired();
this.Property(t => t.Username).HasMaxLength(FieldMaxSize.Username).IsRequired().HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("IX_Username", 1) { IsUnique = true }));
}
When trying to view the model, the error seems to be related to the base class referring to the parent class where the parent requires the base (they reference each other) and the designer doesn't like this, but EF handles it just fine.
PROOF: If I remove the references to "User" in the base class, the designer WILL work (badly)... NOTE... I do get it to work by removing both base class properties referencing the User class and their associated mappings... BUT... the designer STILL MODELS THEM!
So, I remove the User properties (ModifiedBy and CreatedBy) in the base class and I also remove the associated mappings, then the designer builds a graphic representations of the schema ... BUT... it still includes the properties I just commented out (they are clearly cached somewhere)!
PLEASE!
(1) Correct the designer so it doesn't crash on valid schema as provided in the sample
(2) Fix the caching problem with the designer so that it NEVER builds schema for the designer on old/stale code!
Based on this example, the Power Tools designer is completely unreliable as it can clearly build a model that DOES NOT match actual code/schema.
For entity framework >= 6 you need to use Entity framework designer tools http://www.microsoft.com/en-au/download/details.aspx?id=40762

MVC4 Code first approach, how to fix the following?

I am getting the following error
One or more validation errors were detected during model generation:
\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'UserRoles_Roles_Source' in relationship 'UserRoles_Roles'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.
My entities and the associated mappings are defined as follows,
public class UserProfile
{
public UserProfile()
{
UserUserRoles = new List<UserRoles>();
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<UserRoles> UserUserRoles { get; set; }
}
public class Roles
{
public Roles()
{
RoleUserRoles = new List<UserRoles>();
}
public int RoleId { get; set; }
public string RoleName { get; set; }
public virtual ICollection<UserRoles> RoleUserRoles { get; set; }
}
public class UserRoles
{
public int UserId { get; set; }
public int RoleId { get; set; }
public virtual UserProfile User { get; set; }
public virtual Roles Roles { get; set; }
}
//Mappings
public UserProfileMap()
{
// Primary Key
HasKey(t => t.UserId);
// Properties
Property(t => t.UserName)
.HasMaxLength(56);
// Table & Column Mappings
ToTable("UserProfile");
Property(t => t.UserId).HasColumnName("UserId");
Property(t => t.UserName).HasColumnName("UserName");
}
public class RolesMap : EntityTypeConfiguration<Roles>
{
public RolesMap()
{
// Primary Key
HasKey(t => t.RoleId);
// Properties
Property(t => t.RoleName)
.HasMaxLength(256);
// Table & Column Mappings
ToTable("webpages_Roles");
Property(t => t.RoleId).HasColumnName("RoleId");
Property(t => t.RoleName).HasColumnName("RoleName");
}
}
public class UserRolesMap : EntityTypeConfiguration<UserRoles>
{
public UserRolesMap()
{
// Primary Key
HasKey(t => t.UserId);
HasKey(t => t.RoleId);
// Table & Column Mappings
ToTable("webpages_UsersInRoles");
Property(t => t.UserId).HasColumnName("UserId");
Property(t => t.RoleId).HasColumnName("RoleId");
// Relationships
HasRequired(t => t.User)
.WithMany(t => t.UserUserRoles)
.HasForeignKey(d => d.UserId);
HasRequired(t => t.Roles)
.WithMany(t => t.RoleUserRoles)
.HasForeignKey(d => d.RoleId);
}
}
what am I doing wrong?
Per the comments:
A combined primary key should be constructed as HasKey(t => new { t.UserId, t.RoleId });
It looks like you want to create a many-to-many relation between models. In that case you do not need the class UserRoles, it will be generated by EF when using this scenario:
public class User
{
// other properties
public virtual IList<Role> Roles {get;set;}
}
public class Role
{
// other properties
public virtual IList<User> Users {get;set;}
}
However, if you do want the UserRoles model to for instance store additional information you need to make the mapping manually in for example the OnModelCreating() function of the DbContext class.

Defining relationships with existing database in code first

I have an existing database with two tables: MemData and MemPhone.
MemData has the following structure
uidMemberId (PK, uniqueidentifier not null)
strFirstName (varchar(50), null)
strLastName (varchar(50), null)
MemPhone has the following structure
uidMemberId (uniqueidentifier not null)
strPhoneNumber (varchar(50), null)
There's no PK on the MemberPhoneNumber table. The two tables are joined by uidMemberId but no foreign keys have been set up in the database.
My MemData Model looks like this:
[Table("MemData")]
public class Member
{
[Key]
public Guid MemberId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual IList<MemberPhoneNumber> MemberPhoneNumbers { get; set; }
}
With the configuration map looking like this:
public MemberMap()
{
Property(t => t.MemberId).HasColumnName("uidMemberID");
Property(t => t.FirstName).HasColumnName("strFirstName");
Property(t => t.LastName).HasColumnName("strLastName");
HasMany(x => x.MemberPhoneNumbers);
}
My MemPhone Model looks like this:
[Table("MemPhone")]
public class MemberPhoneNumber
{
[Key]
public Guid MemberId { get; set; }
public string PhoneNumber { get; set; }
public virtual Member Member { get; set; }
}
With the configuration map looking like this:
public MemberPhoneNumberMap()
{
Property(t => t.MemberId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(t => t.MemberId).HasColumnName("uidMemberID");
Property(t => t.PhoneNumber).HasColumnName("strPhone");
}
In my MVC app, when I call
Uow.Members.GetAll().Include(p => p.MemberPhoneNumbers).ToList()
I get the following error
Invalid column name 'Member_MemberId'.
It should be looking for MemData_uidMemberId instead but I can't figure out what I've missed in the configuration.
Thanks
By default foreign key name will be propertyName _ entityId. That's why EF tries to map to Member_MemberId column. Provide foreign key configuration for one-to-many relationship
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
ToTable("MemData");
HasKey(m => m.MemberId);
Property(m => m.MemberId).HasColumnName("uidMemberID");
Property(m => m.FirstName).HasColumnName("strFirstName");
Property(m => m.LastName).HasColumnName("strLastName");
HasMany(x => x.MemberPhoneNumbers)
.WithRequired(p => p.Member)
.HasForeignKey(p => p.MemberId);
}
}
Also keep in mind, that you can configure key and table with fluent configuration, you don't need to pollute your entity with data annotations attributes.

Mapping EF Code First to an Existing Database

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.
Tables
AlarmDefinition
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!!!
We ended up ditching EF for now and writing our own custom ADO.NET code.