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

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; }

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

Entity Framework : Code First Approach. Creating Entities using TPT inheritance

I am new to entity framework and I am using code first approach to create entities using TPT inheritance.
My requirement is to create the entities as per the attached diagram where ID is PK for Customers table and FK for the AddressDetails and ContactDetails table. Based on the keys I also need to create the association and navigation properties for the entities. Table Diagram
In my code I have created entities as
public class Customer
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int ZipCode { get; set; }
public virtual ContactDetails ContactDetails { get; set; }
public virtual AddressDetails AddressDetails { get; set; }
}
[Table("ContactDetails")]
public class ContactDetails: Customer
{
public string MobileNo { get; set; }
public string EmailId { get; set; }
}
[Table("AddressDetails")]
public class AddressDetails: Customer
{
public string BillingAddress { get; set; }
public string DeliveryAddress { get; set; }
}
My question is, have I created the association and navigation properties correctly or do I need to add them in the ContactDetails and AddressDetails class as well? Also, when I run the code the entities are getting created in the database but for the Customer table there are 2 additional columns created as AddressDetails_Id(FK,int,null) and ContactDetails_Id(FK,int,null). I think they are created because of the navigation property but I do not need these columns in the database to be created. Also the values are always null in these two columns.
Any help would be appreciated. Thanks in advance.

One-to-one in EF only producing one Foreign Key

I'm attempting to build a 1-1 relationship - a Tenant has a Url, and vice versa:
Models
public class Tenant {
[Key]
[Required]
public int TenantId { get; set; }
public string Name { get; set; }
public virtual Url Url { get; set; }
public int UrlId { get; set; }
}
public class Url {
[Key]
[Required]
public int UrlId { get; set; }
public string Name { get; set; }
public virtual Tenant Tenant { get; set; }
public int TenantId { get; set; }
}
Configs
public class UrlConfiguration : EntityTypeConfiguration<Url> {
public UrlConfiguration() {
HasKey(s => s.UrlId);
}
}
public class TenantConfiguration : EntityTypeConfiguration<Tenant>
{
public TenantConfiguration() {
HasRequired(s => s.Url).WithRequiredPrincipal(s => s.Tenant);
}
}
Result:
I'd expect there to be a foreign key on both models... why is this not the case?
A one-to-one relationship with both ends having required foreign keys cannot exist in a relational database. If saving a new Tenant record requires a URL record, but in order to create that URL record, that URL requires a Tenant record, where will you begin?
Even though on a database level it can't practically exist, this model will still work. From my experience, Entity Framework will enforce the dependency on application level, and will throw an EntityException when it detects that one of the entities you're trying to save has no relationship to one of the other.
It creates this database model so that it can still save your entities, and enforce relationships on an application level.
No, this isn't nice on a database level as the one-to-one constraint won't be enforced there. If you need the database constraints as well, consider merging the tables or redesigning your data structures so that a one-to-one relationship isn't necessary.

Entity Framework Code First: One-to-Many and Many-to-Many relationships to same table

I have a User model and a Event model in my project. The Event has a creator(User) and has participant(Users) so Event has a one-to-many relationship with User and also a many-to-many relationship to the same table.
I had first the one-to-many relationship like this:
Public class Event
{
...
public int CreatedById { get; set; }
public virtual User CreatedBy { get; set; }
...
}
Then when I added the many-to-many relationship the migration doesn't generate the many to many relationship:
Public class User
{
...
public virtual ICollection<Event> Events { get; set; }
...
}
Public class Event
{
...
public int CreatedById { get; set; }
public virtual User CreatedBy { get; set; }
public virtual ICollection<User> Users { get; set; }
...
}
If I remove the one-to-many relationship then the migration generates the many-to-many relationship successfully.
Is there a way to do this with only data annotations?
EF doesn't know where User.Events has to be mapped to. It could be Event.CreatedBy or it could be Event.Users. Both would result in a valid model. You must give EF a little hint what you want by applying the [InverseProperty] attribute:
public class User
{
...
[InverseProperty("Users")]
public virtual ICollection<Event> Events { get; set; }
...
}
With Code First Approach, I would always recommend to use fluent API rather than using DataAnnotations, Which uses some conversions automatically.
This way, you'll know what exact configuration you've made.
If I were you, here is what i would use :
public class EventMap : EntityTypeConfiguration<Event>
{
public EventMap()
{
this.HasRequired(m => m.CreatedBy) // envent must have a creator
.WithMany() // a user can have 0,1 or more events created by him
.HasForeignKey(m => m.CreatedById) // specify property to be used as FK
.WillCascadeOnDelete(true); // delete all events created by user if that specific user is deleted
this.HasMany(m=>m.Users) // an event can have 0,1 or more participants
.WithMany(m=>m.Events) // a user can be a participant in 0,1 or more events
.Map(m => m.MapLeftKey("EventId").MapRightKey("UserId")); // this will generate intermediate table to hold participant information - dbo.EventUser with EventId & UserId
// Cascade Delete is always true for Many to Many mapping. however, it doesn't delete entry in other table, it deletes entry in Joined Table only.
}
}

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

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?