I have a problem with EF at the moment.
I have an existing database and in there is a custom User table called Profiles.
The user is below (I have stripped out most of the properties for easy reading).
public partial class Profile : IdentityUser
{
public Profile()
{
this.Assets = new List<Asset>();
// ...
}
public string CompanyId { get; set; }
// ...
public virtual Company Company { get; set; }
public virtual ICollection<Asset> Assets { get; set; }
// ...
}
and my DbContext looks like this (simplified):
public partial class SkipstoneContext : IdentityDbContext<Profile>
{
static SkipstoneContext()
{
Database.SetInitializer<SkipstoneContext>(null);
}
public SkipstoneContext()
: base("DefaultConnection")
{
}
public DbSet<Asset> Assets { get; set; }
// ...
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// ...
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
modelBuilder.Entity<UserSecret>().HasKey<string>(r => r.UserName);
}
}
And I have a class that looks like this:
public Company()
{
this.Assets = new List<Asset>();
}
public string Id { get; set; }
public string Name { get; set; }
public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public System.DateTime DateCreated { get; set; }
public Nullable<System.DateTime> DateModified { get; set; }
public bool Deleted { get; set; }
public virtual Profile CreatedByProfile { get; set; }
public virtual ICollection<Asset> Assets { get; set; }
}
The problem is that when I run my code, I get an error stating:
Invalid column name 'CreatedByProfile_Id'.
I need to tell the system that the Id column for my custom user is just Id.
I had a mapping file:
public class ProfileMap : EntityTypeConfiguration<Profile>
{
public ProfileMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.Id)
.IsRequired()
.HasMaxLength(128);
this.Property(t => t.CompanyId)
.IsRequired()
.HasMaxLength(128);
this.Property(t => t.CreatedBy)
.IsRequired();
this.Property(t => t.Title)
.IsRequired();
this.Property(t => t.Forename)
.IsRequired();
this.Property(t => t.Surname)
.IsRequired();
this.Property(t => t.Email)
.IsRequired();
this.Property(t => t.CredentialId)
.IsRequired();
// Table & Column Mappings
this.ToTable("Profiles");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.CompanyId).HasColumnName("CompanyId");
this.Property(t => t.CreatedBy).HasColumnName("CreatedBy");
this.Property(t => t.ModifiedBy).HasColumnName("ModifiedBy");
this.Property(t => t.DateCreated).HasColumnName("DateCreated");
this.Property(t => t.DateModified).HasColumnName("DateModified");
this.Property(t => t.LastLoginDate).HasColumnName("LastLoginDate");
this.Property(t => t.Title).HasColumnName("Title");
this.Property(t => t.Forename).HasColumnName("Forename");
this.Property(t => t.Surname).HasColumnName("Surname");
this.Property(t => t.Email).HasColumnName("Email");
this.Property(t => t.JobTitle).HasColumnName("JobTitle");
this.Property(t => t.Telephone).HasColumnName("Telephone");
this.Property(t => t.Mobile).HasColumnName("Mobile");
this.Property(t => t.Photo).HasColumnName("Photo");
this.Property(t => t.LinkedIn).HasColumnName("LinkedIn");
this.Property(t => t.Twitter).HasColumnName("Twitter");
this.Property(t => t.Facebook).HasColumnName("Facebook");
this.Property(t => t.Google).HasColumnName("Google");
this.Property(t => t.Bio).HasColumnName("Bio");
this.Property(t => t.CompanyName).HasColumnName("CompanyName");
this.Property(t => t.CredentialId).HasColumnName("CredentialId");
this.Property(t => t.IsLockedOut).HasColumnName("IsLockedOut");
this.Property(t => t.IsApproved).HasColumnName("IsApproved");
this.Property(t => t.CanEditOwn).HasColumnName("CanEditOwn");
this.Property(t => t.CanEdit).HasColumnName("CanEdit");
this.Property(t => t.CanDownload).HasColumnName("CanDownload");
this.Property(t => t.RequiresApproval).HasColumnName("RequiresApproval");
this.Property(t => t.CanApprove).HasColumnName("CanApprove");
this.Property(t => t.CanSync).HasColumnName("CanSync");
this.Property(t => t.AgreedTerms).HasColumnName("AgreedTerms");
this.Property(t => t.Deleted).HasColumnName("Deleted");
this.Property(t => t.UserName).HasColumnName("UserName");
// Relationships
this.HasRequired(t => t.Company)
.WithMany(t => t.Users)
.HasForeignKey(d => d.CompanyId);
}
}
but if I add that to my DbContext class I get an error stating:
A configuration for type 'Models.Profile' has already been added. To
reference the existing configuration use the Entity() or
ComplexType() methods.
I assume this is simple to fix, so could someone point me in the right direction please?
Cheers,
/r3plica
The problem is at your Company class configuration.
Try:
public class CompanyMap : EntityTypeConfiguration<Company>
{
public CompanyMap()
{
// Add this
this.HasRequired(x => x.CreatedByProfile).WithMany().Map(
x => x.MapKey("CreatedByProfileId"));
// CreatedByProfileId is the FK column in the Company table that points
// to the Profile table. This is my made up name for the column since
// I don't know the real name in your database.
}
}
If you don't have a configuration class for Company then in your OnModelCreating method you need:
modelBuilder.Entity<Company>().HasRequired(x => x.CreatedByProfile).WithMany().Map(
x => x.MapKey("CreatedByProfileId"));
UPDATE
Since you already have the property in your class.
modelBuilder.Entity<Company>().HasRequired(
x => x.CreatedByProfile).WithMany().HasForeignKey(x => x.CreatedBy);
Related
I have been trying to establish an optional One-to-One relationship between 2 entities unsuccessfully. I can do it by creating a Unique Constraint on the RTUDEVICE tables DeviceId, but I am trying to do it the "right way" through the Fluent API
What am I doing wrong?
Relationship Explanation:
One DEVICE record may have one-and-only-one record in the RTUDEVICE table.
ENTITIES:
Below are simplified versions of the actual classes...
public partial class Device
{
public Int Id { get; set; }
public string DeviceName { get; set; }
public virtual RTUDevice RTUDevice { get; set; }
}
public partial class RTUDevice
{
public Int Id { get; set; }
public int DeviceId { get; set; }
public bool IsCRMAlarmDevice { get; set; }
public bool HasCustomRegisters { get; set; }
public bool HasGasQualityRegisters { get; set; }
public bool HistoryVerified { get; set; }
public virtual Device Device { get; set; }
}
MAPPING:
I did many attempts using various online example without success...the failing code is commented-out.
public DeviceMap(DbModelBuilder modelBuilder)
{
ToTable("Device", "dbo")
.HasKey(m => m.Id);
Property(m => m.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(m => m.DeviceName)
.IsUnicode(false)
.HasMaxLength(100)
.IsRequired()
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("UX_Device_AlternateKey") { IsUnique = true }));
//modelBuilder.Entity<RTUDevice>()
// .HasOptional(e => e.Device)
// .WithRequired(e => e.RTUDevice)
// .WillCascadeOnDelete(true);
}
public RTUDeviceMap(DbModelBuilder modelBuilder)
{
ToTable("RTUDevice", "dbo")
.HasKey(m => m.Id);
Property(m => m.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(e => e.DeviceId)
.IsRequired();
Property(e => e.IsCRMAlarmDevice )
.IsRequired();
Property(e => e.HasCustomRegisters)
.IsRequired();
Property(e => e.HasGasQualityRegisters)
.IsRequired();
Property(e => e.HistoryVerified)
.IsRequired();
// One-to-Zero-or-One relationship
//modelBuilder.Entity<RTUDevice>()
// .HasOptional(e => e.Device)
// .WithRequired(e => e.RTUDevice)
// .WillCascadeOnDelete(true);
// One-to-Zero-or-One relationship
//modelBuilder.Entity<RTUDevice>()
// .HasRequired(e => e.Device)
// .WithMany()
// .HasForeignKey(c => c.DeviceId)
// .WillCascadeOnDelete(true);
}
You should just use Id as the PK (as well as FK) in RTUDevice entity and get rid of DeviceId. Then define the relationship as follows:
modelBuilder.Entity<Device>()
.HasKey(it => it.Id);
modelBuilder.Entity<RTUDevice>()
.HasKey(it => it.Id);
modelBuilder.Entity<Device>()
.HasOptional(it => it.RTUDevice)
.WithRequired(it => it.Device);
If DeviceId needs to be used explicitly for mapping, use the following:
modelBuilder.Entity<Device>()
.HasOptional(it => it.RTUDevice)
.WithOptionalPrincipal(it => it.Device)
.Map(it => it.MapKey("DeviceId"));
I have a comment class that contains a user object for the comment author / last person to modify the comment.
public class Comment
{
public int CommentId { get; set; }
public int SignOffId { get; set; }
public string CommentText { get; set; }
public int LastModifiedByUserId { get; set; }
public DateTime LastModifiedOnDate { get; set; }
public virtual User LastModifiedByUser { get; set; }
}
I'm trying to setup the relationship in the CommentMap class but I can't figure out how to do it without putting a virtual Comment property in the User class. But I don't want this because it doesn't make sense from the business logic for the User class to have a Comment object.
LastModifiedByUserId is the foreign key in the Comments table pointing to the User table.
Here's the CommentMap ctor.
public CommentMap() {
// Primary Key
this.HasKey(t => t.CommentId);
// Properties
this.Property(t => t.CommentText)
.IsRequired()
.IsMaxLength();
this.Property(t => t.LastModifiedByUserId)
.IsRequired();
this.Property(t => t.LastModifiedOnDate)
.IsRequired();
// Table & Column Mappings
this.ToTable("Comments");
this.Property(t => t.CommentId).HasColumnName("CommentId");
this.Property(t => t.SignOffId).HasColumnName("SignOffId");
this.Property(t => t.CommentText).HasColumnName("CommentText");
this.Property(t => t.LastModifiedByUserId).HasColumnName("LastModifiedByUserId");
this.Property(t => t.LastModifiedOnDate).HasColumnName("LastModifiedOnDate");
// Relationships
this.HasRequired(c => c.LastModifiedByUser)
.WithRequiredDependent(u => u.UserId) //This doesn't work
.HasForeignKey(c => c.LastModifiedByUserId);
}
It wants an entity in the WithRequiredDependent line, not an integer. Is this completely the wrong way to setup this relationship? When I pull a comment from the db I want it to also grab the User object for the person who last modified the comment.
I don't think that a user can only modify one comment. Because that's what your model expresses. The combination HasRequired - WithRequiredDependent expresses a 1:1 relationship. It should be 1:n, as follows:
this.HasRequired(c => c.LastModifiedByUser)
.WithMany()
.HasForeignKey(c => c.LastModifiedByUserId);
I am working on assigning a relationship between two objects but I am getting an error on the mapping.
I have the following objects:
public abstract class EntityBase : IEntity
{
public int Id { get; set; }
}
public class ManagerUser : EntityBase
{
public string UserCode { get; set; }
public string Title { get; set; }
public virtual Staff StaffDetails { get; set; }
}
public class Staff : EntityBase
{
public string UserCode { get; set; }
public string DOB { get; set; }
}
public class ManagerUserMap : EntityMapBase<ManagerUser>
{
protected override void SetupMappings()
{
base.SetupMappings();
//this.HasKey(t => t.UserCode);
this.ToTable("ManagerUsers");
this.Property(t => t.Id).HasColumnName("ManagerUsersID")
.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
this.Property(t => t.Title).HasColumnName("txtTitle");
this.HasRequired(x => x.StaffDetails)
.WithMany()
.HasForeignKey(x => x.UserCode);
}
}
public class StaffMap : EntityMapBase<Staff>
{
protected override void SetupMappings()
{
base.SetupMappings();
//this.HasKey(t => t.UserCode);
this.ToTable("TblStaff");
this.Property(t => t.Id).HasColumnName("StaffID")
.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
this.Property(t => t.UserCode).HasColumnName("User_Code");
this.Property(t => t.DateOfBirth).HasColumnName("dob");
}
}
I am getting the following error:
The type of property 'UserCode' on entity 'ManagerUser' does not match
the type of property 'Id' on entity 'Staff' in the referential
constraint 'ManagerUser_StaffDetails'
I have searched around and failed to find a solution to get it to compare the the foreign key in ManagerUser with the UserCode property in Staff instead of the ID property.
Your keys are a bit messed up in the fluent config, HasKey sets the primary key for the entity. Below I have set the primary key to be Id for both entities. Then use the Usercode as a FK:
public class ManagerUserMap : EntityMapBase<ManagerUser>
{
protected override void SetupMappings()
{
base.SetupMappings();
this.HasKey(t => t.Id);
this.ToTable("ManagerUsers");
this.Property(t => t.Id).HasColumnName("ManagerUsersID")
.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
this.Property(t => t.Title).HasColumnName("txtTitle");
this.HasRequired(x => x.StaffDetails)
.WithMany()
.HasForeignKey(x => x.UserCode);
}
}
public class StaffMap : EntityMapBase<Staff>
{
protected override void SetupMappings()
{
base.SetupMappings();
this.HasKey(t => t.Id);
this.ToTable("TblStaff");
this.Property(t => t.Id).HasColumnName("StaffID")
.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
this.Property(t => t.UserCode).HasColumnName("User_Code");
this.Property(t => t.DateOfBirth).HasColumnName("dob");
}
}
I have a solution that I have been creating for a while and I have used EF Code First migrations to create the database. Recently for another solution my supervisor ran some scripts on the database that added a few tables. Now, I need to connect to those tables in my solution. I have this code here:
public class RoleMap : EntityTypeConfiguration<Role>
{
public RoleMap()
{
//Primary key
this.HasKey(t => t.RoleId);
this.Property(t => t.ApplicationId)
.IsRequired();
this.Property(t => t.Description)
.HasMaxLength(256);
this.Property(t => t.RoleName)
.IsRequired()
.HasMaxLength(256);
this.Property(t => t.LoweredRoleName)
.IsRequired()
.HasMaxLength(256);
this.ToTable("aspnet_Roles");
this.Property(t => t.RoleId).HasColumnName("RoleId");
this.Property(t => t.ApplicationId).HasColumnName("ApplicationId");
this.Property(t => t.Description).HasColumnName("Description");
this.Property(t => t.LoweredRoleName).HasColumnName("LoweredRoleName");
this.Property(t => t.RoleName).HasColumnName("RoleName");
}
}
static DataContext()
{
Database.SetInitializer<DataContext>(null);
}
public DataContext(): base("DefaultConnection")
{
}
public DbSet<Role> Roles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new RoleMap());
}
I found this code in this link:
http://www.codeproject.com/Tips/661053/Entity-Framework-Code-First-Map
Unfortunately, when I try to create a new migration - it is trying to create a new table (even though I told it the table already exists).
public partial class addRoles : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.aspnet_Roles",
c => new
{
RoleId = c.Guid(nullable: false),
ApplicationId = c.Guid(nullable: false),
Description = c.String(maxLength: 256),
LoweredRoleName = c.String(nullable: false, maxLength: 256),
RoleName = c.String(nullable: false, maxLength: 256),
})
.PrimaryKey(t => t.RoleId);
}
public override void Down()
{
DropTable("dbo.aspnet_Roles");
}
}
With the help of JamieD77 I found the solution. It is a combination of the code first mapping found in this link:
Code First Mapping
and then here, add -ignorechanges when add-migration
Code First Migrations With Existing Table
I have two tables, Configuration and Device. Device has a string property called Name. A configuration can have many devices. I want an index on the Name property, and the name must be unique within a configuration. So I want an index on multiple columns in the Device table, namely on Configuration_ID and Name.
class Configuration
{
Guid ID { get; set; }
List<Device> Devices { get; set;
}
class Device
{
Guid ID { get; set; }
string Name { get; set;
}
class ConfigurationMap : EntityTypeConfiguration<Configuration>
{
ConfigurationMap()
{
this.HasKey(t => t.ID);
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.HasMany(t => t.Devices).WithRequired().WillCascadeOnDelete(true);
}
}
class DeviceMap
{
DeviceMap()
{
this.HasKey(t => t.ID);
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(t => t.DisplayName)
.HasColumnName("Name")
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("NameIndex")))
.HasMaxLength(450);
// Where to put the other index?
}
}
My two questions are:
Is this a good idea at all? ;)
How can I do that using fluent API?
Add ConfigurationId property to Device class (foreign key). Then, in cofiguration, for both ConfigurationId and Name properties do:
Property(t => t.Name).HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("IDX_ConfigurationId_Name", 0) { IsUnique = true }));
Property(t => t.ConfigurationId).HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("IDX_ConfigurationId_Name", 1) { IsUnique = true }));