I have postgres database with some data in it.
I'm using Npgsql.EntityFramework7 adapter (version 3.1.0-beta8-2) to handle it.
The problem is when I try to get entity from context which has some enum inside of it.
In postgres I declare enum:
CREATE TYPE public.my_enum AS
ENUM ('value1','value2','value3');
My model looks like:
[Table("my_table")]
public class Entity
{
[Column("id")]
[Key]
public int Id { get; set; }
[Column("type")]
public MyEnum Type { get; set; }
}
Enum:
public enum MyEnum
{
value1,
value2,
value3
}
Unfortunately, when I try to get something from database via entity framework I receive this kind of error:
System.InvalidCastException: Can't cast database type
my_enum to Int32
I've tried to register my enum in Npgsql (as it's pointed in npgsql documentation). With no effects.
Is there something I can do to handle 'proper' enums with this stack? (to have enum fields in database as strings/enums not as ints)
Related
public class MyClass : ISelfReferenceable<Guid>
{
public Guid Id {get;set;}
public Guid? ParentId {get;set;}
}
public interface ISelfReferenceable<TId>
{
TId Id {get;set;}
TId? ParentId {get;set;}
}
Can anyone explain to me why the above does not work?
It shouts Compiler Error CS0738
'type name' does not implement interface member 'member name'. 'method name' cannot implement 'interface member' because it does not have the matching return type of ' type name'.
on MyClass.ParentId, saying that it doesn't implement ISelfReferenceable.ParentId, unless I change MyClass.ParentId from Guid? to Guid.
Currently, I get around this by using two generic types, one for Id and another for ParentId, or simply make ParentId Guid instead of Guid?.
Is this the right approach and is there a better way of doing this?
The problem is that TId? is interpreted as a nullable reference type (in fact this is more complicated and depends on the language version and whether you are in a nullable context. See also the explanation under default constraint). You can fix it by adding a where TId : struct generic type constraint to the interface. But of course this limits the applicable types to value types. A string Id would not be possible.
The error also goes away if you declare
public class MyClass : ISelfReferenceable<string>
{
public string Id { get; set; }
public string? ParentId { get; set; }
}
I don't know if it suits your purpose, but it compiles with this:
public interface ISelfReferenceable<TId> where TId : struct
{
TId Id {get;set;}
TId? ParentId {get;set;}
}
Remember that Guid is a value type.
I got the following types
internal enum IssueType
{
First,
Second,
Special
}
internal class Issue
{
public int Id { get; set; }
public string Title { get; set; }
public IssueType Type { get; set; }
}
internal class SpecialIssue : Issue
{
public string Payload { get; set; }
}
Some issue types map to certain subclasses, like Special would map to SpecialIssue in this case. Others just map to Issue i.e. there are several IssueTypes without special subclasses.
Now I would like to have an Issues table to hold all these issues so I configured Issue.Type as a discriminator value.
builder.HasDiscriminator(x => x.Type)
.HasValue<Issue>(IssueType.First)
.HasValue<Issue>(IssueType.Second)
.HasValue<SpecialIssue>(IssueType.Special);
Unfortunately it seems that I cannot set multiple discriminator values for the same type so at runtime I get errors stating that some discriminators weren't mapped although I did.
What I would like to achieve is to map all subclasses to their respective discriminators and have some kind of "fallback" that maps to Issue (or just map any remaining IssueType to the Issue type manually).
Is it possible to achieve this? I couldn't figure out any way to get EFCore to do this.
I'm currently using EFCore 5.0.10.
I'm trying to serialize a non-primitive property (struct) within an entity and Entity Framework just does not serialize it.
UPDATE: Reformulating the question and sharing the affected code.
public class ClassToPersist
{
public int Id { get; set; }
public ValueWrapper SomeValue { get; set; }
}
public struct ValueWrapper
{
public Guid Value { get; set; }
}
And in my OnModelCreating function I just declare:
modelBuilder.Entity<SomeClass>();
The result of this is not a compile, nor runtime error, Entity Framewrok just skips serializing the SomeValue field.
Please note that ValueWrapper is a struct. If I convert it to a class, it works properly by "flattening" the data inside it.
Is it that "custom" structs can't be serialized? Is it a limitation of the library or maybe there's a way to specify the serialization convention to use in this case?
Good day,
I have been learning some Entity Framework and I came to this code
public class Test
{
public int Id { get; set; }
public string name { get; set; }
public testEnum testEnum { get; set; }
}
public enum testEnum {
numero1=1,
numero2=2
}
Then I run add-migration xxxxx and update-database, the problem is that when I go to SQL server, I can not see the enum anywhere.
My questions are:
1.What happened with the enum and how can I see it in SQL server?
2. When do I use enum instead of a table like the following:
public class EnumReplace{ public int Id { get; set; }
public int value{ get; set; }
}
thank you.
1.What happened with the enum and how can I see it in SQL server?
The enum gets stored in the database table as an integer. You wouldn't be able to see the enumeration in the database. EF takes the responsibility of casting the underlying type to the enumeration defined while retrieving the values from the database.
In Entity Framework, an enumeration can have the following underlying types: Byte, Int16, Int32, Int64 , or SByte.
Read more about enum support in EF code first here
2. When do I use enum instead of a table like the following:
When we have a predefined set of values allowed for a property/field, we usually use enumeration. For e.g.
enum Days
{
Sat,
Sun,
Mon,
Tue,
Wed,
Thu,
Fri
};
You could also use Flagged Enums, Read more about enum here.
you have to have the enum in your class. something like this:
public testEnum MyProperty{ get; set; }
so basically you can't have enum as a table. you can have enum as a type of one of your properties in a table.
We have been using EF CF for a while in our solution. Big fans! Up to this point, we've been using a hack to support enums (creating an extra field on the model; ignore the enum durring mapping; and map the extra field to the column in the db that we would have used). Traditionally we have been storing our enums as strings(varchars) in the DB (makes it nice and readable). Now with enum support in EF 5 (Beta 2) it looks like it only supports mapping enums to int columns in the DB....Can we get EF 5 to store our enums as their string representation.
Where "Type" is an enum of type DocumentType
public enum DocumentType
{
POInvoice,
NonPOInvoice,
Any
}
I tried to map it using:
public class WorkflowMap : EntityTypeConfiguration<Model.Workflow.Workflow>
{
public WorkflowMap()
{
ToTable("Workflow", "Workflow");
...
Property(wf => wf.Type).HasColumnType("varchar");
}
}
I thought was going to be the magic bullet but..
That just throws:
Schema specified is not valid. Errors: (571,12) : error 2019: Member
Mapping specified is not valid. The type
'Dodson.Data.DataAccess.EFRepositories.DocumentType[Nullable=False,DefaultValue=]'
of member 'Type' in type
'Dodson.Data.DataAccess.EFRepositories.Workflow' is not compatible
with
'SqlServer.varchar[Nullable=False,DefaultValue=,MaxLength=8000,Unicode=False,FixedLength=False]'
of member 'Type' in type 'CodeFirstDatabaseSchema.Workflow'.
Your thoughts?
This is currently not possible. Enum in EF has same limitations as enums in CLR - they are just named set of integer values. Check this article for confirmation:
The EF enum type definitions live in conceptual layer. Similarly to
CLR enums the EF enums have underlying type which is one of Edm.SByte,
Edm.Byte, Edm.Int16, Edm.Int32 or Edm.Int64 with Edm.Int32 being the
default underlying type if none has been specified.
I posted article and related suggestion about this problem. If you want to see this feature in the future please vote for the suggestion.
I hit this problem a few weeks ago. The best I could come up with is a bit hacky.
I have a Gender enum on the class Person, and I use data annotations to map the string to the database and ignore the enum.
public class Person
{
public int PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[Column("Gender")]
public string GenderString
{
get { return Gender.ToString(); }
private set { Gender = value.ParseEnum<Gender>(); }
}
[NotMapped]
public Gender Gender { get; set; }
}
And the extension method to get the correct enum from the string.
public static class StringExtensions
{
public static T ParseEnum<T>(this string value)
{
return (T)Enum.Parse(typeof(T), value, true);
}
}
See this post for full details - http://nodogmablog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/