Reusing a column for a required property with Entity Framework 6.0, Fluent API, and DataAnnotations - entity-framework

I have a base class
public class BaseClass
{
public int Id {get; set;}
}
and two derived classes
public class Foobar: BaseClass
{
[Required]
public int Whatever {get; set;}
}
public class Snafu: BaseClass
{
[Required]
public int Whatever {get; set;}
}
I'm using Table Per Hierarchy inheritance and trying to cut down on my duplicate columns, so with Fluent API I've mapped them like so:
modelBuilder.Entity<Foobar>().Property(fb => fb.Whatever).HasColumnName("Whatever");
modelBuilder.Entity<Snafu>().Property(sf => sf.Whatever).HasColumnName("Whatever");
However, this results in
(137,10) : error 3023: Problem in mapping fragments starting at line 137:Column BaseClass.Whatever in table BaseClass must be mapped: It has no default value and is not nullable.
In EF6 this type of mapping seems to work fine if I take off the [Required] attribute from both subclasses. Adding a [DefaultValue(0)] attribute to both derived classes does not fix the problem.
Any idea how to get these properties to share a column in the database while maintaining their required attribute?

This is actually a bug in EF6. In EF5 the scenario used not to work at all (we would throw an exception in the lines of "column names need to be unique"). While in EF6 we did some work to enable it, but apparently we missed the fact that the shared column has to be nullable in the database even if the property is required in the derived types. The latter is because unless the base class is abstract, you need to be able to store an instance of the base type and for any instance of the base type the column should be null.
I have filed the issue in our bug database:
https://entityframework.codeplex.com/workitem/1924
Feel free to vote for it.
As for a workaround, if having an intermediary type is not an option, you can mark the column as nullable explicitly appending a call to .IsOptional() on the entity configurations. This won't give you exactly what you want because for the purpose of EF data validation this call to IsOptional() on the fluent API will override the [Required] data annotation. However, other flavors of data validation, such as MVC's validation will still honor the attribute.
There are other possible workarounds that I haven't tried, maybe if it is acceptable to use TPT and have both derived types have Whatever live in a different table this would work. I believe any approach that relies on setting a default value won't help because the bug is not only about the table schema not being able to hold an instance of the base class, it is also about the EF mapping generated by Code First not being valid.
UPDATE: This will be fixed in Entity Framework version 6.1.0 which is currently available in beta.

Introducing another type, which contains the required property shared by the other two accomplishes what you're looking for. The entities then look this:
public class BaseClass
{
public int Id { get; set; }
}
public abstract class BaseIntermediaryClass : BaseClass
{
[Required]
public int Whatever { get; set; }
}
public class Foobar : BaseIntermediaryClass
{
}
public class Snafu : BaseIntermediaryClass
{
}
And the mappings like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BaseIntermediaryClass>().Property(fb => fb.Whatever).HasColumnName("Whatever");
base.OnModelCreating(modelBuilder);
}
Full code of working example can be found here: https://gist.github.com/trayburn/7923392

Related

Using a common class for inheritance and for a member (code-first)

I've having difficulties getting EF code-first to generate a database from the following entities:
public class Person : Animal
{
public int Id { get; set; }
public Animal Pet { get; set; }
}
public class Animal
{
public string Name { get; set; }
}
So conceptually a person is an animal with a name, and they have a pet that is also an animal with a name. My context contains an array of people but not animals, which is why Animal doesn't contain a key:
public DbSet<Person> People { get; set; }
If I try to create a database using code-first I get the following error:
System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:
MyProject.Database.Animal: : EntityType 'Animal' has no key defined. Define the key for this EntityType.
Animals: EntityType: EntitySet 'Animals' is based on type 'Animal' that has no keys defined.
If I remove the Pet field I get a table with Id and Name fields, which is my expected behavior. Similarly, if I remove the Animal inheritance I get a table with Id and Pet_Name fields, which is again my expected behavior. What I'm trying to get is a table with Id, Name and Pet_Name fields.
Can't help but feel I'm missing something very basic here, because I've done this on other ORMs without issue. Can anyone tell me how to do this with EF 6.2?
For anyone else that reads this in future EF treats classes as either Entities or Complex Types. Entities get their own table while complex types get their own fields added as fields to the classes of parents that contain them as properties. If you declare a class instance as a property of another then EF immediately assumes it's an Entity; if it sees you trying to use it as a base class in an inheritance hierarchy then it assumes it's a complex type. The error shown above occurs when EF has already erroneously assumed that the type is an Entity but you then try to use it as a complex type. Seems to me that EF shouldn't be making the assumption in the first place if the class has no key property, but there it is. The solution is to simply flag it as a complex type from the start in your OnModelCreating function:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.ComplexType<Animal>();
base.OnModelCreating(modelBuilder);
}

Entity Framework table splitting - how to initialize lazy-loaded properties?

Using Entity Framework 6.0, I am attempting to implement table splitting to improve query performance on tables with columns that contain BLOB data. I have followed the recommendations in this tutorial and it does indeed work as described.
Here's a very simplified example of the entity classes that map to one of my split tables ...
public class MyEntity
{
public string Id { get; set; }
public virtual MyEntityContent Content { get; set; }
public string Name { get; set; }
}
public class MyEntityContent
{
public string Id { get; set; }
public virtual MyEntity Entity { get; set; }
public byte[] Blob { get; set; }
}
... and the corresponding configuration code in the associated DbContext implementation ...
modelBuilder.Entity<MyEntity>().HasKey(e => e.Id).ToTable("MyEntities");
modelBuilder.Entity<MyEntityContent>().HasKey(c => c.Id).ToTable("MyEntities");
modelBuilder.Entity<MyEntity>().HasRequired(e => e.Content).WithRequiredPrincipal(d => d.Entity);
Given that the lazy-loaded Content property is Required by Entity Framework, it seems sensible to initialize it to a default value in the constructor of the containing MyEntity class ...
public MyEntity()
{
Content = new MyEntityContent();
}
... which enables a new instance of the class to be created and partially populated, without the risk of an exception being thrown by forgetting to initialize the required property value:
var entity = new MyEntity {Id = "XXX", Name = "something"};
I typically use a similar technique to initialize collection properties on EF entities and it works fine. However, in the above scenario, this initialization in the constructor has an unexpected effect: when retrieving existing entity instances from the database, the database value in the lazy-loaded property is ignored in favor of the empty default value.
This seems illogical to me. Doesn't Entity Framework create an entity object by first calling its default constructor and then applying its own property values to the created instance? If so, this should overwrite my default Content property value with a new instance of MyEntityContent, based on database data. This is how it seems to work with lazy-loaded collection properties.
If it's not possible to do this in the way I am expecting, is there an alternative technique for initializing lazy-loaded properties?
Don't initialize virtual members and perhaps, if you have to, handle any exceptions from uninitialized members.
I just had this issue with an entity with two virtual fields. Originally I had it initialize those two, but after removing them (and initializing the other fields to some default value), it started working for me. Try it out and let me know!
[Edit] I just realized I replied this to a slightly old post, didn't see the date. I guess I'll leave this answer here in case.

Why the frequent unexplained use of the partial modifier in EF Code First?

In the EF Code first docs and examples, you'll frequently see classes and methods defined using the partial modifier. For example, the following
public partial class Department
{
public int DepartmentID { get; set; }
public DepartmentNames Name { get; set; }
public decimal Budget { get; set; }
}
I understand the general use of the partial keyword by the C# compiler. However, I often see these examples without applying that functionality (i.e., the class is never re-opened elsewhere).
In other examples, I have also seen partial modifiers on methods as well.
Do these modifiers carry some special meaning in an EF Code First context? Can anyone help me understand what's going on?
Given EF makes working with POCOs really easy, this makes it flexible in terms of separating components and pieces. For example, a section that defines your models:
public partial class PurchaseOrder
{
public Int32 ID { get; set; }
public String CustomerName { get; set; }
public Double InvoiceAmount { get; set; }
public virtual ICollection<PurchaseOrderItem> Items { get; set; }
}
Then apply business logic elsewhere:
public partial class PurchaseOrder : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// ...
}
}
And maybe extend its functionality another place still:
public partial class PurchaseOrder
{
public void AddItem(PurchaseOrderItem item)
{
// ...
}
}
though as #E.J. Brennan mentions, it's more likely they were generated from a T4 template. This means that anything you did in the generated file would be wiped with every generation; however, if you left the generated item alone, you could still extend it (like I've shown with IValidatableObject or additional methods) without worrying if your changes would be lost.
It wouldn't be unusual to use T4, or another code generator to create the basic classes that map back to your database. If one did that, you would want those classes to be partial so that you could extend those classes in a seperate file - if you extended those classes in the original file, they would get overwritten every time you re-generated the file.
If you hand coded your classes, there would be no need to use the partial on all of them.
You can extend Entity Framework generated types:
The classes only contain properties that are defined in the conceptual model and do not contain any methods. The generated classes are partial.
So, in your new partial classes (not the generated ones) you can define business logic, display attributes, validation logic etc. These classes won't be overwritten, like the generated ones.

Entity framework code first creates "discriminator" column

I am using EF CF approach for a website with MySQL.
For some reason EF creates a column in my Post table called "Discriminator" and contains the VARCHAR "Post".
Why is this column created? Can I do something to avoid it being created? Are there any advantages of having this column?
The Discriminator column is used and required in Table-Per-Hierarchy inheritance scenarios. If you for example have a model like this ...
public abstract class BaseEntity
{
public int Id { get; set; }
//...
}
public class Post : BaseEntity
{
//...
}
public class OtherEntity : BaseEntity
{
//...
}
... and make the BaseEntity part of the model, for instance by adding a DbSet<BaseEntity> to your derived context, Entity Framework will map this class hierarchy by default into a single table, but introduce a special column - the Discriminator - to distinguish between the different types (Post or OtherEntity) stored in this table. This column gets populated with the name of the type (again Post or OtherEntity).
You can stop the column being created by adding the [NotMapped] data annotation to the models that are inheriting from your base class. This will tell EF not to add your class to future migrations, removing the discriminator column.
public class BaseClass
{
}
[NotMapped]
public class InheritingClass : BaseClass
{
}
For completeness, if you want to use the fluent API to stop the inheriting class from being mapped with entity (and therefore stopping the discriminator column being created) you can do the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<InheritingClass>();
}

Code first TPC Inheritance with concrete base and derived, concrete types in EF

I'm trying to set up a TPC inheritance using Code First to model incoming and outgoing messages and the records therein.
The base type, SentRecord, is concrete and its derived type, ReceivedRecord, is also concrete and inherits from SentRecord and adds a few extra fields in order to record return codes. Something like this, but with more properties:
public class SentRecord : RecordBase {
public int Id { get; set; }
public string FooField { get; set; }
}
public class ReceivedRecord : SentRecord {
public int ReturnCode { get; set; }
public SentRecord SentRecord { get; set; }
}
The current model is TPH and as a result the tables get a descriminator column to identify the type of object that was persisted. It works, but I'd prefer both objects to be stored in separate tables, without the need of the discriminator column. The table SentRecord would only have the columns Id and FooField and the table ReceivedRecord would have Id, FooField, ReturnCode and an FK to SentRecord.
I currently have the following in my DataContext class:
public class Context : DContext {
public DbSet<SentRecord> SentRecords { get; set; }
public DbSet<ReceivedRecord> ReceivedRecords { get; set; }
}
And I have the following configuration for the ReceivedRecord:
public class ReceivedRecord_Configuration : EntityTypeConfiguration<ReceivedRecord>{
public ReceivedRecord_Configuration() {
this.Map(m => {
m.MapInheritedProperties();
m.ToTable("ReceivedRecords");
});
}
}
And the following for SentRecord:
public class SentRecord_Configuration : EntityTypeConfiguration<SentRecord>{
public SentRecord_Configuration() {
this.Map(m => {
m.MapInheritedProperties(); //In order to map the properties declared in RecordBase
m.ToTable("SentRecords");
});
}
}
But once I run this, I get the following error when EF is trying to initialize my database:
Problem in mapping fragments starting at lines 455, 1284:
An entity from one EntitySet is mapped to a row that is also mapped to an entity from another EntitySet with possibly different key.
Ensure these two mapping fragments do not map two unrelated EntitySets to two overlapping groups of rows.
I'm not sure what to do in order to set this up in the TPC way I described above? Or should I stick with TPH which works?
Thanks in advance!
Okay, I got it up and running. Truth be told, the example I gave was a little bit less complex than the actual classes and inheritance hierarchy I was working with. That hierarchy contained a lot of abstract classes and concrete classes from which other classes inherited.
'Flattening' the hierarchy by getting cutting down on inheritance made it work smooth and without any errors whatsoever. Response messages aren't inherited from the sent messages anymore.
Short version: Don't make complex inheritance trees with mixed concrete and abstract base types when trying to use code-first database models. It'll only make it more complex to persist.