Can non-integer enums be used in Entity Framework? - entity-framework

I'm using Entity Framework 6.1 (.NET 4.5) and noticed something strange:
A simple enum property in an entity class works fine when defined like this:
public enum TestEnum
{
ValueOne,
ValueTwo
}
//then used in an entity class like this:
public class MyClass
{
public TestEnum MyTestEnum { get; set; }
}
... but not when it's defined as a non-int32 type, like this:
public enum TestEnum : ushort
...
With the former, Entity Framework detects and maps the property automatically to an int column. With the latter, EF doesn't even detect that the property exists in the entity class. If I try to force it,
...Property(x => x.MyTestEnum).IsRequired();
I get the following migration error:
The property 'MyTestEnum' is not a declared property on type 'MyClass'. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property.
So are ushort enums not supported in EF?

Related

Code First creates int instead of enum

I want to create a enum type column named 'type' but when I reverse engineer my Code First generated DB it assigns it as an 'int'.
Here is my Enum class:
[Flags]
public enum TypeNames
{
Een = 0,
Twee = 1,
Drie = 2
}
Here is my Grounds class to create the table with the 'TypeNames'-enum. The Properties class is another table (Grounds - Properties have a TPT inheritance).
[Table("gronden")]
public partial class Grounds : Properties
{
[Column("opp")]
public double? Surface { get; set; }
[EnumDataType(typeof(TypeNames)), Column("type")]
public TypeNames Types { get; set; }
}
Any ideas of what I am missing here to get an enum-type into my DB?
According to the following answer, it appears that EnumDataTypeAttribute is only implemented for ASP.NET UI components, and not for EF usage.
Should the EnumDataTypeAttribute work correctly in .NET 4.0 using Entity Framework?
EF Core 2.1 implements a new feature that allows Enums to be stored as strings in the database. This allows data to be self-describing, which can be really helpful for long-term maintainability. For your specific case, you could simply do:
[Table("gronden")]
public partial class Grounds : Properties
{
[Column("opp")]
public double? Surface { get; set; }
[Column("type", TypeName = "nvarchar(24)")]
public TypeNames Types { get; set; }
}
You can find more detail on this page:
https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions
Also, I noticed that you have the FlagsAttribute set on your enum. Are you hoping to be able to apply multiple enum values to a single entity? This should work fine when values are persisted as an int, but will not work if storing as a MySQL ENUM or string datatype. MySQL does support a SET datatype, but it seems unlikely that EF would add support for this feature, since most other databases don't have a similar concept.
https://dev.mysql.com/doc/refman/5.6/en/constraint-enum.html
If you do indeed want to allow multiple enum values to be applied to each entity (similar to the way tags are used on Stack Overflow), you might consider creating a many-to-many relationship instead. Basically, this would mean converting the TypeNames enum into a Types table in the database, and allowing EF to generate a GroundTypes table to link them together. Here is a tutorial:
http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx

The type 'Company.Model.User' and the type 'Company.Core.Model.User' both have the same simple name of 'User' and so cannot be used in the same model

I have a base entity class MyCompany.Core.Model.User which is to be used for common properties of a User entity:
public class User
{
public string Username { get; set; }
public string Usercode { get; set; }
}
I also have a base mapping class MyCompany.Core.Model.UserMap to setup the code first mappings for the base User class:
public class UserMap<TUser> : EntityMapBase<TUser>
where TUser : User
{
public UserMap()
{
// Primary Key
this.HasKey(t => t.Usercode);
// Table & Column Mappings
this.ToTable("Users");
this.Property(t => t.Username).HasColumnName("Username");
this.Property(t => t.Usercode).HasColumnName("UserCode");
}
}
In a separate assembly I have a derived class MyCompany.Model.User that inherits from the base User class and extends it with some additional properties:
public class User : Core.User
{
public string Surname { get; set; }
}
In addition I have a derived mapping class MyCompany.Model.UserMap to provide the additional configuration for the additional properties:
public class UserMap : Core.UserMap<User>
{
public UserMap()
{
this.Property(t => t.Surname).HasColumnName("Surname");
}
}
However when adding MyCompany.Model.User to the context and registering the MyCompany.Model.UserMap I'm getting the following error:
The type 'MyCompany.Model.User' and the type 'MyCompany.Core.Model.User' both have the same simple name of 'User' and so cannot be used in the same model. All types in a given model must have unique simple names. Use 'NotMappedAttribute' or call Ignore in the Code First fluent API to explicitly exclude a property or type from the model.
This link indicates that you can't have the same "simple name" in the model twice.
Why is the base class "simple name" being registered in the model, and is there a way around it in order to implement this sort of entity inheritance?
I suspect the simple solution would be to rename the derived class; however I would prefer to avoid this as there may be many derivations in multiple contexts.
Note: Using Entity Framework 6.0.0-rc1 (prerelease)
This is a limitation of EF that I reported in 2012 https://entityframework.codeplex.com/workitem/483 that is still not implemented in 6.0.2. EF uses a flat internal architecture and does not recognize namespaces. Might be coming in EF7 but not before. For now the only solutions is to rename the two classes to unique class names irrespective of the namespace they are in. IMHO, this is an significant limitation within EF. Just consider a class named Category and how many different namespaces it could be used within across a domain.
First read Table type mappings
The hierarchical implementation model options need to be understood first.
Then look at the IGNORE option. You may or may not need depending on chosen approach.
requires ignore ???
modelBuilder.Ignore<BaseXYZ>()
Ef is currently trying to include your base class to support an included Type that inherits from a NON abstract class.
This happens also if you forget to explicitly add a namespace in your class. Running on EF 6.4.4 and i can differentiate through namespaces.
e.g.
public class MyClass {}
Instead of:
namespace somenamespace
{
public class MyClass {}
}
To keep same class name I suggest to use different interfaces. An interface for the Core.Entity defining the common properties and an other interface for the extra properties. So instead of using a derived class you use a class implementing the two interfaces.
if you have 2 or more classes with a relationship between them like this:
public class A{
public X attribute1 {get;set;}
public B b {get;set;}
}
public class B{
public X attribute1 {get;set;}
}
sometimes in this situation it raises this error,
Solution :
change X name in one class.

How would EF handle computed property?

Given the following class
public class Model
{
public int ActualInt{get;set;}
public int ComputedInt {get {return ActualInt * 2;}}
}
How would EF not map the ComputedInt.
I also would prefer not suly my domain model with NotMappedAttribute
Fluent is also a pain because I have to keep removing the mapping per context, per computed property and there are a lof of those in the domain model.
Is there a way to do this, simply by convention instead of configuring explicitly?

Summary column on EF

Is it possible to add summary properties(no database column) according LINQ from another property(column) in EF generated class from database and this property don't update(delete or remove from class) when update model from database(because this property(cloumn) is not on database)
Yes, it is. Classed generated by Entity Framework as an Entitied are always marked partial. It lets you extend the functionality with your own properties or method.
Let say your entity class is named Post. You can extend it with code like that:
public partial class Post
{
public int Average
{
get
{
return this.Items.Average();
}
}
}
Because it's not a part of designer-generated file it won't be overwritten when it's regenerated. However, there is one requirement to make it work: your custom part of Post class has to be in exactly the same namespace as code generated by EF.
Try using the [NotMapped] attribute on a property in a partial class. This will be ignored by Entity Framework.
public partial class EntityName
{
[NotMapped]
public int CalculatedProperty
{
get
{
return Numbers.Sum();
}
}
}

Adding custom property to object returned from WCF RIA Services

I have a stored procedure in my Entity Framework Model. I've added a Function Import and mapped the results to a Complex Type.
I want to add an extra property to this Complex type, that I'll populate in my Domain Service, not coming back from the stored procedure. I added a myClass.shared.cs file and implemented added the property like so:
//myClass.shared.cs
public partial class myClass
{
public string myProperty {get;set;}
}
I populate this in my domain service when I return the object, e.g.:
public myClass GetMyClass(int myClassID)
{
myClass theClass= this.ObjectContext.StoredProc(myClassID).FirstOrDefault();
class.myProperty = 12345;
return theClass;
}
When I get the return values of this method on the client side theClass.myProperty is always null but all values from the stored procedure are populated, am I missing something?
I've tried decorating the myProperty with the [DataMember] attribute but this throws the error:
"The type 'myClass' already contains a
definition for 'myProperty'"
How can I get this to return the value set in the Domain Service to the client?
There was no need to put this in the shared.cs class. The shared.cs class copies the actual code over to the client side and is useful for adding methods etc. but to add a new property, all I had to do was add a partial class (NOT in myClass.shared.cs) and decorate it with DataMember.
public partial class myClass
{
[DataMember]
public string myProperty {get;set;}
}