CLARIFICATION: I am not attempting to store a Class/Type in a database field, or use the Class/Type itself as the key value. I am trying to use a single property of the Class/Type (in this instance, a Guid) as the key.
Although I don't think it's strictly relevant to this particular issue, it may be useful for context: I am trying to implement Semantic Types in my latest project. I have had some success throughout my code, and have in fact identified a couple of bugs that would probably not have been identified quickly as a result.
All is well with integrating my Semantic Types with EF6 in non-key fields, with the help of some Fluent API code.
However, when attempting to use a Semantic Type for a key field, EF generates a runtime exception, stating that there is no key defined - when clearly there is.
With a simple Guid as key
Here is an example of an EF entity I used which does not use Semantic Types:
public partial class MyEntity
{
[Key]
public Guid id { get; set; }
public string SomeData { get; set; }
}
The above works fine.
With a Type property as key - Attempt #1
Now, I define a new Semantic Type, as follows:
public class MyEntityId: SemanticType<Guid>
{
public MyEntityId()
: base(IsValid, Guid.Empty)
{ }
public MyEntityId(Guid value)
: base(IsValid, value)
{ }
public static bool IsValid(Guid value)
{
return true;
}
}
... and update the EF model accordingly.
public partial class MyEntity
{
[Key]
public MyEntityId id { get; set; }
public string SomeData { get; set; }
}
I then add some code to the DbContext OnModelCreating method to map the MyEntityId.Value to the required column name:
modelBuilder
.Entity<MyEntity>()
.Property(x => x.MyEntityId.Value)
.HasColumnName("id");
Now, all of the above compiles fine. But as soon as there is an interaction with the table, I get the following exception:
An exception of type 'System.Data.Entity.ModelConfiguration.ModelValidationException'
occurred in EntityFramework.dll but was not handled in user code
EntityType 'MyEntity' has no key defined. Define the key for this MyEntity.
Clearly, the entity does have a key defined.
With a Type property as key - Attempt #2
So, I tried removing the [key] attribute from the model, and modified the Fluent API code, as follows:
modelBuilder
.Entity<MyEntity>()
.HasKey(x => x.MyEntityId.Value);
.Property(x => x.MyEntityId.Value)
.HasColumnName("id")
But this code then generates the following exception:
An exception of type 'System.InvalidOperationException' occurred in
EntityFramework.dll but was not handled in user code
Additional information: The properties expression 'x => x.MyEntityId.Value'
is not valid. The expression should represent a property:
C#: 't => t.MyProperty' VB.Net: 'Function(t) t.MyProperty'.
When specifying multiple properties use an anonymous type:
C#: 't => new { t.MyProperty1, t.MyProperty2 }'
VB.Net: 'Function(t) New With { t.MyProperty1, t.MyProperty2 }'.
With a Type property as key - Attempt #3
So, after digging around on SO, it looks like EF requires a property, not just a public field. So I modified the Semantic Type to introduce a new "EFValue" property, as follows:
public class MyEntityId: SemanticType<Guid>
{
public MyEntityId()
: base(IsValid, Guid.Empty)
{ }
public MyEntityId(Guid value)
: base(IsValid, value)
{ }
public static bool IsValid(Guid value)
{
return true;
}
public Guid EFValue
{
get { return Value; }
}
}
... and modified the Fluent API code, as follows:
modelBuilder
.Entity<MyEntity>()
.HasKey(x => x.MyEntityId.EFValue);
.Property(x => x.MyEntityId.Value)
.HasColumnName("id")
But then I get the same 'System.InvalidOperationException' exception.
Is it not possible to define the property of a Type like this as a Primary Key in EF6?