How to configure EF 5.0 code first to create separate table with each enum type - entity-framework

I've used the following enum in my code first models
public enum Role
{
Reviewer = 1,
Requester = 2,
Approver = 3
}
It is used in the User entity like below
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public Role Role { get; set; }
}
EF creates a single table Users in the database and role is stored there as int.
What I need here is another table named "Roles" with Id and Desc. Id is the value of the enum and Desc is its name. And this table will be automatically populated on model creation.
Does EF has some feature for it? Or do I have to create another entity for Role and populate that manually?

Related

Linking objects in .net core api

I'm trying to display a child object in my .net core api application. I have the following setup;
public class Accounts
{
[Key]
public int AccountId { get; set; }
public string AccountName { get; set; }
public int AccountStatusId { get; set; }
public List<AccountStatus> AccountStatus { get; } = new List<AccountStatus>();
}
public class AccountStatus
{
public int AccountStatusId { get; set; }
public string AccountStatusName { get; set; }
}
Which is being displayed in my controller link this:
[HttpGet]
public IEnumerable<Accounts> Get()
{
return this._internalContext.Accounts.ToList();
}
It works, but I expected AccountStatus to be shown in the result with the AccountStatusName item to use in my json API. As it stands, it returns this:
{
"accountId": 1,
"accountName": "Toms Mega Mix",
"accountStatusId": 1,
"accountStatus": []
},
Where I expceted it to do something like this:
{
"accountId": 1,
"accountName": "Toms Mega Mix",
"accountStatusId": 1,
"accountStatus": [{"AccountStatusName":"Active"}]
},
Account Status return
{
"accountStatusId": 1,
"accountStatusName": "Customer"
},
{
"accountStatusId": 2,
"accountStatusName": "Supplier"
},
{
"accountStatusId": 3,
"accountStatusName": "Ex Customer"
}
Presumably I have to link them somehow but can't work out how
It is not a general .NET Core question but is an Entity Framework Core
question.
UPDATE
Based on our conversation in the chat, it looks like you just need just one AccountStatus per Account.
So, this should work:
public class Accounts
{
[Key]
public int AccountId { get; set; }
public string AccountName { get; set; }
// Optional ID property for Entity Framework navigation to another table. If you don't define it, it will be implicitly created by Entity Framework
public int AccountStatusId { get; set; }
public AccountStatus AccountStatus { get; set; }
}
Previous answer:
To load data from another table, Entity Framework needs to join tables. It's a bit more "expensive" than just querying one table.
So, you need to tell EF to do it for you. For example, you can explicitly load data from a related table by using .Include().
this._internalContext.Accounts
// In general, this should help:
.Include(a => a.AccountStatus)
.ToList();
In your particular example, you also need to fix the Accounts class if you want one-to-many relationship. When many accounts can have one status.
AccountStatus property should be like that:
public class Accounts
{
[Key]
public int AccountId { get; set; }
public string AccountName { get; set; }
public virtual ICollection<AccountStatus> AccountStatus { get; set; }
}
In general, if you want to have many-to-many relationship for any reason, you need to introduce an intermediate entity (and table) for that.
Let's imagine, we have a Course entity. Then you can have many accounts assigned to one course. And each account can be assigned to many courses. It is a many-to-many relationship.
At the same time you have account status per account.
So, the diagram will look like:
AccountToCourse entity is required for many-to-many relationship between Account and Course entities.
Check out more details on that and more ways of controlling the data load behavior:
Microsoft Docs / Entity Framework Core / Query data / Query related data

Using enum as FK on EF 6

I'd like to use an enum as Foreign Key in a Code-First app. Since enums are stored as int, I thought I could use the attribute [ForeignKey] on the enum property, but it throws this exception:
The types of all properties in the Dependent Role of a referential constraint
must be the same as the corresponding property types in the Principal Role
Here is an example of what I am trying to do:
public enum UserType
{
Administrator = 1,
Member = 2
}
public class User
{
public int UserId { get; set; }
public string Login { get; set; }
[ForeignKey("TypeDetails")]
public UserType Type { get; set;}
public virtual MasterType TypeDetails { get; set; }
}
public class MasterType
{
public int MasterTypeId { get; set; }
public string Description { get; set; }
...
}
Is it possible to do this or something similar through fluent api or migrations?
Thanks
Here's one I made earlier: https://www.nuget.org/packages/ef-enum-to-lookup
It's a nuget package that provides a method you can call in your Seed (initializer and/or migrations) which will automatically build lookup tables and add FKs where the enum is used. Usage info.
Enjoy :-) And let me know if it works for you (or anyone else for that matter!)

Invalid Column Name with EF

I modified the table UserProfile in the database with some extra columns and then modified the UserProfile class to reflect them:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
public string School { get; set; }
}
Obviously they are FirstName, Surname and School. For some reason though despite the register action saving details into all 3 of these new columns when I try to load the data via:
var context = new UsersContext();
var user = context.UserProfiles.First(n => n.UserName == model.UserName);
It says that School is an invalid ColumnName. I checked it was a string in both class and table so bit confused how to debug, help!
(Continued from comments on OP)
Rather than doing this manually, you should consider using the EF migrations framework - There are a number of benefits and it's more future-proof in case internal EF functionality changes.
See here for more information on migrations

Do all associated objects have to be accessed (lazyloaded) before an existing object can be saved?

I'm learning EF Code First and am having trouble when updating existing records. I've boiled it down to this simple example:
This works:
using(var db = new DataContext()){
var p = db.People.Find(1);
p.Name="New Name";
Console.WriteLine(p.Gender.Name); //<--Unnecessary property access
db.SaveChanges(); //Success
}
...but this fails (when the WriteLine is removed):
using(var db = new DataContext()){
var p = db.People.Find(1);
p.Name="New Name";
db.SaveChanges(); //DbValidationError "Gender field is required."
}
Why do I have to access/load the Gender propery if I'm not using it and the data is already correctly stored in the database? I just want to change the Name on an existing record. In this example, Gender is a one-to-many association stored as Gender_Id in the People table. The classes are defined like this:
public class Person
{
[Key]
public int PersonId { get; set; }
[Required, MaxLength(50)]
public string Name { get; set; }
[Required, Column("Gender")]
virtual public GenderCode Gender { get; set; }
}
public class GenderCode
{
[Key]
public int Id { get; set; }
[Required, MaxLength(10)]
public string Name { get; set; }
}
public class DataContext:DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<GenderCode> GenderCodes { get; set; }
}
Of course, the fully defined classes are to have many more fields. I'd rather not have to access every dependant property every time I want to modify an unrelated value.
Is there a way to load an object, change a field, and save it without loading all related objects first?
Yes, this is necessary because of some horrible design mistakes in EF.
Check out my similar question, EF: Validation failing on update when using lazy-loaded, required properties
One trick is declaring FK properties along with the OO relations:
[ForeignKey("GenderId"), Column("Gender")]
virtual public GenderCode Gender { get; set; }
[Required]
public int GenderId { get; set; }
It is because you are using data annotations and Required attribute has also meaning for validation. Once you set navigation property as Required by data annotation it must be filled / loaded when you are going to persist entity to the database.

Fluent API, EF 4.1: a problem of inheritance and foreign key

There are several simple classes:
The first class:
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
// ...
public ICollection<Topic> Topics { get; set; }
}
The second class:
public class Publication
{
public int PublicationId { get; set; }
public string Title { get; set; }
/ ...
public User Author { get; set; }
}
The third class:
public class Topic: Publication
{
public string TopicContent { get; set; }
// ...
}
After creating a database for my model I have the following stucture of the database:
Users
UserId
UserName
Publications
PublicationId
Title
TopicContent
Author_UserId
User_UserId
As you can see I get two fields Author_UserId and User_UserId having identical role in the table Publications.
How can I merge this fields into one field using Fluent API or Data Annotation?
I don't think that it's possible to have the same foreign key column in the Publications table. Publication.Author and User.Topics cannot be the endpoints of one and the same association. You could have a Publication instance which isn't a Topic and a reference to a User:
User user = new User() { Topics = new List<Topic>() };
Publication publication = new Publication();
publication.Author = user;
user.Topics.Add(???);
At ??? you can't add publication because it isn't a Topic instance. user.Topics must refer to another object than publication which means that those endpoints cannot belong to the same association.
Edit
If you want only one single association with only a single foreign key column in the database you must either move the Author property from Publication to Topic or let the collection in your User class refer to Publication instead of Topic:
public ICollection<Publication> Publications { get; set; }