invalid column name in .net while using inheritance - c#

I have a problem mapping a relationship
while reverse engineering in visual studio .net
I use inheritance:
public class Quiz : Component
{
public QuizQuestion rootQuestion { get; set; }
public override String getType() { return "quiz"; }
}
the property rootQuestion is not specified in the motherclass, it only exists in the subclass
Quiz doesn't exist as a table in my sqlserver database(only the QuizQuestions and Component table exists in the database, (my teacher told me to do it like this for
the java part of this project).
But I want the subclass Quiz to have a property rootQuestion that refers to quizRootQuestion in my database. So here's what I did:
public class QuizMapper : EntityTypeConfiguration<Quiz>
{
public QuizMapper()
{
this.HasKey(t => t.ComponentID);
this.HasOptional(c => c.rootQuestion)
.WithMany().Map(m => m.MapKey("quizRootQuestionID"));
}
}
public class QuizQuestionMap : EntityTypeConfiguration<QuizQuestion>
{
public QuizQuestionMap()
{
// Properties
// Table & Column Mappings
this.HasKey(t => t.QuestionID);
this.ToTable("QuizQuestions");
this.Property(t => t.QuestionID).HasColumnName("questionID");
}
}
I get this error when i'm trying to run in my browser:
Invalid column name 'rootQuestion_QuestionID'.
Tables in my database:
Component:
componentId
quizRootQuestionID
TypeId(=discriminator)
QuizQuestions
questionID
question
Can someone please tell me what I am doing wrong?

You would get exactly this exception if you forgot to add the QuizMapper to the model builder configuration in OnModelCreating of your derived context:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new QuizMapper());
modelBuilder.Configurations.Add(new QuizQuestionMap());
}

Related

Entity Framework 6, cannot use Ignore method on the property

Currently, I'm using ASP Identity with MVC 5.I want to remove phone number field from the AspNetUsers table, but when I use add-migration command it causes the following error.
You cannot use Ignore method on the property 'PhoneNumber' on type
'Models.DbModel.User' because this type inherits from the type
'Microsoft.AspNet.Identity.EntityFramework.IdentityUser`
I have already read tons of questions on here, but all of them said you have to ignore property in your base class, however, I don't have any access to the base in this case.
How can I solve this problem?
Update: when I used fluent API inside the OnModelCreating method it worked, I don't want to use it this way so I separated the config class for each entity.
Below is my code:
Derived Entity Class
public class User: IdentityUser
{
public ICollection<Comment> Comments { get; set; }
}
Config class
public sealed class UserConfig : EntityTypeConfiguration<User>
{
public UserConfig()
{
ToTable("dbo", "Users");
Ignore(x => x.PhoneNumber);
Ignore(x => x.PhoneNumberConfirmed);
}
}
Context Class
public class WebsiteContext : IdentityDbContext
{
public WebsiteContext()
: base("XYZ")
{
}
public DbSet<Comment> Comment { get; set; }
//public DbSet<User> User { get; set; }
public static WebsiteContext Create()
{
return new WebsiteContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new CommentConfig());
modelBuilder.Configurations.Add(new UserConfig());
}
}
Try the [NotMapped] attribute from
System.ComponentModel.DataAnnotations.Schema
This might get you around that limitation , it has been used to ignore Enums in the mapping, this might not be exactly what you want

Entity Framework Table Per Class Inheritance

I am trying to implement a history table for an entity in EF6, code first.
I figured there would be a way to do this with inheritance. The history table, which is a derived type of the actual table entity, just containing straight copies of all the properties. Along with an edit to the key.
My code first table entity config for Booking.
public class BookingEntityConfiguration
: EntityTypeConfiguration<Booking>
{
public BookingEntityConfiguration()
{
Property(b => b.BookingId).HasColumnOrder(0);
HasKey(b => new { b.BookingId });
HasOptional(b => b.BookingType)
.WithMany()
.HasForeignKey(c => c.BookingTypeId);
}
}
My code first table entity config for BookingHistory.
public class BookingHistoryTypeEntityConfiguration
: EntityTypeConfiguration<BookingHistory>
{
public BookingHistoryTypeEntityConfiguration()
{
Property(b => b.BookingId).HasColumnOrder(0);
Property(b => b.BookingVersion).HasColumnOrder(0);
HasKey(b => new { b.BookingId, b.BookingVersion });
}
}
Where
public class BookingHistory : Booking { }
My BookingHistory table never gets generated in the contexts associated database, which includes these references to the table entities:
public DbSet<Booking> Bookings { get; set; }
public DbSet<BookingHistory> BookingHistories { get; set; }
Is there any simple way to achieve what I want? Which is the derived entity (history table) generates a table that contains the same column fields as the base class entity, but with a change of key.
I appreciate my code above is pretty naive, but I can't seem to find a blog post of similar to help.
The best way is to have a base type from which both the entity and its history entity inherit:
public class BookingsContext : DbContext
{
public DbSet<Booking> Bookings { get; set; }
public DbSet<BookingHistory> BookingHistories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BookingBase>()
.HasKey(p => p.BookingId)
.Property(p => p.BookingId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Booking>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Booking");
});
modelBuilder.Entity<BookingHistory>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("BookingHistory");
});
}
}
By ToTable you specify that both entities should be mapped to different tables. On top of that, MapInheritedProperties tells EF to mapp all properties from the base type to this table as well. the result is two completely independent tables that can be addressed by two separate DbSet properties.

Code-first: Mapping entities to existing database tables

I am using Entity Framework 6 code-first with an existing database, but having problems mapping my entities to the database tables.
Normally, I would use database-first approach and have my entity and context code generated, but using the designer has become a huge pain.
I have set Database.SetInitializer(null) as I do not want EF to change my schema.
Database schema:
Code-first:
public class Project
{
public int ProjectId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class ReleaseControlContext : DbContext
{
public ReleaseControlContext()
: base(ConfigurationManager.ConnectionStrings["ReleaseControl"].ConnectionString)
{
Database.SetInitializer<ReleaseControlContext>(null);
}
public DbSet<Project> Projects { get; set; }
}
Calling code:
using(var context = new ReleaseControlContext())
{
var projects = context.Projects.ToList();
}
The following exception is thrown:
SqlException: Invalid object name 'dbo.Projects'.
This is because my database table is Project and not Projects. I don't want to rename my context's DbSet<Project> to "Project" because that would be semantically incorrect.
Question:
Do I have to use the fluent API/data annotations to map between the Project database table and the DbSet<Project> Projects collection?
You can use the
[Table("Project")]
public class Project {
....
}
annotation against the Project entity, or in the OnModelCreating(DbModelBuilder modelBuilder) you can call modelBuilder.Entity<Project>().ToTable("Project");.
Both would do the same thing.
You should define a class (ie:ProjectMap) that inherits from the generic class EntityTypeConfiguration(T) where T is here your Project class.
In this ProjectMap class, you can define explicitly a table mapping :
this.ToTable("Project", "dbo");
The class ProjectMap should be called in the following method of your DbContext class
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ProjectMap());
}

ModelValidationException: Name 'AnonymousUID' cannot be used in type 'CodeFirstDatabaseSchema.AnonymousUID'

I am using Entity Framework to model an existing database. One of the database tables contains a column with the same name as the table, AnonymousUID.
I use the Entity Framework Power Tools function Reverse Engineer Code First to generate the model classes and mappings. The reverse engineering procedure automatically renames the AnonymousUID class member (to AnonymousUID1) to avoid that a member name is the same as the class name. The generated model class thus looks like this:
public partial class AnonymousUID
{
public string UID { get; set; }
public string AnonymousUID1 { get; set; }
}
and the EF mapping constructor is implemented like this:
public AnonymousUIDMap()
{
// Primary Key
this.HasKey(t => t.UID);
// Properties
this.Property(t => t.UID).IsRequired().HasMaxLength(64);
this.Property(t => t.AnonymousUID1).IsRequired().HasMaxLength(64);
// Table & Column Mappings
this.ToTable("AnonymousUID");
this.Property(t => t.UID).HasColumnName("UID");
this.Property(t => t.AnonymousUID1).HasColumnName("AnonymousUID");
}
The database context class is implemented like this:
public partial class MyDbContext : DbContext
{
// Constructors...
public DbSet<AnonymousUID> AnonymousUIDs { get; set; }
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new AnonymousUIDMap());
...
}
}
This is all good and well, and the code builds without problems. But when I try to access arbitrary contents of the database:
using (var context = new MyDbContext())
{
var foos = from foo in context.Foos select foo;
...
}
the following exception is nonetheless thrown:
System.Data.Entity.ModelConfiguration.ModelValidationException :
One or more validation errors were detected during model generation:
\tAnonymousUID: Name: Name 'AnonymousUID' cannot be used in type
CodeFirstDatabaseSchema.AnonymousUID'. Member names cannot be the
same as their enclosing type.
There is obviously some additional mapping build-up going on in CodeFirstDatabaseSchema, and this procedure is not able to avoid the class/member name clash.
Why does this error occur? After all, the reverse engineering procedure managed to circumvent the naming issue.
Without modifying the schema of the already established database, is there some way I can avoid this exception from being thrown?
I am using Entity Framework 6.0 (pre-release) from Nuget in a .NET Framework 4 project.
As I guessed at in the comment above, change the column name to start with a lowercase 'a'
...HasColumnName("anonymousUID");
Let's hope this is a pre release defect and is fixed in the RTM ;-)
Is the code you displayed the only place you're using the AnonymousUID name? What is the name of your DbSet in the generated DbContext?
I built a test app, and didn't get any errors, here it in it's entirety:
public partial class AnonymousUID
{
[Key]
public int UID { get; set; }
public string AnonymousUID1 { get; set; }
}
public class Model : DbContext
{
public DbSet<AnonymousUID> AnonymousUIDs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<AnonymousUID>()
.Property(a => a.AnonymousUID1)
.HasColumnName("AnonymousUID");
modelBuilder.Entity<AnonymousUID>()
.ToTable("AnonymousUID");
}
}
class Program
{
static void Main(string[] args)
{
var model = new Model();
var a = new AnonymousUID();
a.AnonymousUID1 = "hello world";
model.AnonymousUIDs.Add(a);
model.SaveChanges();
var applications = model.AnonymousUIDs.ToList();
Console.WriteLine(applications.Count);
Console.ReadLine();
}
}
Created this database:
It was able to create, insert, and then display the count of the table.
I had a similar issue, but I could not rename the column because it would break legacy code. The type names that Power Tools generated are all lowercase. I changed the capitalization on the conflicting types, and it worked.
I suspect that CodeFirstDatabaseSchema is maintaining lowercase property names, but I am not sure. All I know is that changing my lowercase type names to properly capitalized type names fixed it. I hope that is helpful for someone.

Is it possible to use a PK column as a discriminator in Entity Framework code first?

I'm trying to use Entity Framework code first to try to map a simple lookup table to a heirarchy of types and want to use the primary key of the table as the discriminator column for a "table per heirarchy" entity. More acturately, I'm trying to make this work against an existing database.
Here is a contrived sample app I put together trying to figure out if I can make it work or not:
using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
namespace EfTest
{
public abstract class Base
{
public int LookupId { get; set; }
public String Name { get; set; }
public abstract String GetTest();
}
public class Derived1 : Base
{
public override string GetTest() { return Name + "1"; }
}
public class Derived2 : Base
{
public override string GetTest() { return Name + "2"; }
}
public class Derived3 : Base
{
public override string GetTest() { return Name + "3"; }
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
using(var context = new MyContext())
{
foreach (var item in context.Lookups)
{
Console.WriteLine("{0} {1} {2}", item.LookupId, item.Name, item.GetType().FullName);
}
}
Console.ReadKey();
}
}
public class MyContext : DbContext
{
public DbSet<Base> Lookups { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var config = modelBuilder.Entity<Base>();
config.HasKey(e => e.LookupId).ToTable("dbo.Lookup");
config.Property(e => e.LookupId)
.HasColumnName("LookupId")
.IsRequired()
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
config.Property(e => e.Name)
.IsRequired()
.HasColumnName("Name")
.HasMaxLength(32)
.HasColumnType("varchar");
config.Map<Derived1>(e => e.Requires("LookupId").HasValue(1).IsRequired());
config.Map<Derived2>(e => e.Requires("LookupId").HasValue(2).IsRequired());
config.Map<Derived3>(e => e.Requires("LookupId").HasValue(3).IsRequired());
//config.Map<Derived1>(e => e.Requires("Name").HasValue("Item1").IsRequired());
//config.Map<Derived2>(e => e.Requires("Name").HasValue("Item2").IsRequired());
//config.Map<Derived3>(e => e.Requires("Name").HasValue("Item3").IsRequired());
}
}
}
However, this raises an exception stating:
Problem in mapping fragments starting at line 24:Condition member
'Base.LookupId' with a condition other than 'IsNull=False' is mapped.
Either remove the condition on Base.LookupId or remove it from the
mapping.
I've also tried discrimiating with the "Name" column with similar results.
The errors look like it complaining that I'm trying to map to nullable column in the database, however, the table that actually gets created has both columns marked not null, as I would expect.
Is what I'm trying to do simply not supported by EF?
This is not possible. Each column can have only single special purpose in the mapping. Having a column as a key and discriminator are two special purposes. Discriminator column has special meaning of selecting the correct type to be materialized and because if that it must not be present in mapped entity (you cannot set it from your application). Also having discriminator on column which must be unique is incorrect.

Categories