EF 4 Code First - How do I model this? - entity-framework

I am trying out EF and Code First approach
I have an Account model which looks like
public class Account
{
public virtual int AccountID {get; set;}
public virtual string AccountName {get; set;}
public virtual Account ParentAccount {get; set;}
public virtual Contact AccountOwner {get; set}
}
Contact class is a simple class
public class Contact
{
public virtual int ContactID {get; set;}
public virtual string ContactName {get; set;}
}
Now I have no idea how to add IDs to the account class.
Suppose I have set up the context correctly, what modifications are needed to the Account class so that
I can add an Account as the parent of another Account
I can access the ParentAccount of a particular Account
I can access the AccountOwner of a particular Account
I am new to this. Any help would be appreciated

Here's how I would solve this.
Add foreign key properties to your classes. I'm talking about ParentAccountId and AccountOwnerId. To make navigating things a bit easier, I have also added a collection of child accounts to Account and a collection of owned accounts to Contact. Note that it's not necessary to make "normal" properties virtual. Only navigational properties should be made virtual.
public class Account
{
public int AccountID {get; set;}
public string AccountName {get; set;}
public int? ParentAccountId { get; set; }
public int? AccountOwnerId { get; set; }
public virtual Account ParentAccount { get; set; }
public virtual ICollection<Account> ChildAccounts { get; set; }
public virtual Contact AccountOwner { get; set; }
public Account()
{
ChildAccounts = new List<Account>();
}
}
public class Contact
{
public int ContactID { get; set; }
public string ContactName { get; set; }
public virtual ICollection<Account> OwnedAccounts { get; set; }
public Contact()
{
OwnedAccounts = new List<Account>();
}
}
Next, create a mapping for the Account class to explain to EF how to setup the relationships.
public class AccountMapping : EntityTypeConfiguration<Account>
{
public AccountMapping()
{
HasOptional(x => x.ParentAccount).WithMany(x => x.ChildAccounts).HasForeignKey(x => x.ParentAccountId);
HasOptional(x => x.AccountOwner).WithMany(x => x.OwnedAccounts).HasForeignKey(x => x.AccountOwnerId);
}
}
Finally, add the mapping to your DbContext class.
public MyContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
public DbSet<Contact> Contacts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new AccountMapping());
}
}
Note that I have assumed that the AccountOwner and ParentAccount are optional. If they are required, simply change the type of the foreign properties from int? to int and change the HasOptional in the mappings to HasRequired.

public class Account
{
[Key]
public virtual int AccountID {get; set;}
public virtual string AccountName {get; set;}
public virtual Account ParentAccount {get; set;}
public virtual Contact AccountOwner {get; set}
public virtual IEnummerable<Account> ChiledAccount {get; set}
}
public class Contact
{
[Key]
public virtual int ContactID {get; set;}
public virtual string ContactName {get; set;}
}

You can do this by without using Fluent API.That is by default conventions are maintained by EF.B'cos your mappings are simple.
You're having Account (1) : Contact (m) Relationship.
So try with below models
public class Account
{
public int Id {get; set;}
public string AccountName {get; set;}
public virtual ICollection<Contact> AccountOwners { get; set; }
}
public class Contact
{
public int Id {get; set;}
public string ContactName {get; set;}
public virtual Account ParentAccount {get; set;}
}
Then Your database tables will be created like below:
Accounts Table
Id int NotNull
AccountName nvarchar(100) AllowNull
Contacts Table
Id int NotNull
ContactName nvarchar(100) AllowNull
Account_Id int NotNull
If you need to do advance mappings then you have to learn Fluent API.

Related

Many to zero relationship with Entity Framework

I have difficulty understand how I can make a "connecting" table between TimeLogEntity and TimeLogPeriodEntity (see classes below).
public class TimeLogEntity
{
public int Id {get; set;}
public DateTime Date { get; set; }
...
public TimeLogPeriodEntity TimeLogPeriod { get; set; }
}
public class TimeLogPeriodEntity
{
public int Id {get; set;}
public string Name {get; set; }
public DateTime From {get; set; }
public DateTime To {get; set; }
...
public ICollection<TimeLogEntity> TimeLogs{ get; set; }
}
I want EF to generate 3 tables: TimeLogs, TimeLogPeriods and TimeLogPeriodCrossTimeLogs,
I want a TimeLogPeriod to have multiple TimeLogs. But a TimeLog don't have to have a TimeLogPeriod.

EF Core join table for one-to-many relationship

I have the following classes: User, Post and UserPost. User and Post have a 1-to-many relationship. There's a third join table called UserPost that tracks the up/down vote each post gets. To ensure each user can only upvote/downvote once, the ID (PK) of this table is a composite key of User and Post ID.
public class User {
public Guid Id {get; set;}
public string UserName {get; set;}
public ICollection<Post> Posts {get; set;}
}
public class Post {
public Guid Id {get; set;}
public string Content {get;set;}
public User User {get; set;}
}
public UserPost {
public Guid Id {get; set;} // This should be a composite key of User ID and Post ID
public Guid PostId {get;set;}
public Guid UserId {get;set;}
public VoteType VoteType {get; set;}
}
public enum VoteType {
Up = 1,
Down = 0
}
In my DB Context class I defined the User/Post relationship like this:
builder.Entity<User>()
.HasMany(u => u.Posts)
.WithOne(p => p.User)
Now I want to define the relationship for the UserPost model but not sure how to go about it. So far I have:
builder.Entity<UserPost>()
.HasKey(x => new { x.UserId, x.PostId })
Does it require anything further?
Write your whole relationship as follows:
public class User
{
public Guid Id {get; set;}
public string UserName {get; set;}
public ICollection<Post> Posts {get; set;}
}
public class Post
{
public Guid Id {get; set;}
public string Content {get;set;}
public Guid UserId {get; set;}
public User User {get; set;}
}
public UserVote // Rename this from UserPost to UserVote to keep naming consistency.
{
public Guid PostId {get;set;}
public Guid UserId {get;set;}
public VoteType VoteType {get; set;}
public Post Post {get; set;}
public User User {get; set;}
}
public enum VoteType {
Up = 1,
Down = 0
}
Now, Fluent API configuration for the UserVote as follows:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<UserVote>(e =>
{
e.HasKey(uv => new { uv.PostId, uv.UserId}); //<-- Here is the composite key.
e.HasOne(uv => uv.Post).WithMany().HasForeignKey(uv => uv.PostId).OnDelete(DeleteBehavior.Restrict);
e.HasOne(uv => uv.User).WithMany().HasForeignKey(uv => uv.UserId).OnDelete(DeleteBehavior.Restrict);
});
}

Mapping Relationships with EF Core Fluent API with two entities of the same type

I have been trying to use the fluent api to configure appropriate mapping for the image below. (If someone marks this as a duplicate, for the love of all that is holy, please include the relevant link! I've spent days combing stackoverflow.)
A main thought I am aiming for is that all entities will have an EnterpriseID that would be used as a sharding key.
The Enterprise table contains two Contacts, a PrimaryContact and a BillingContact.
What I would like to do is create a new Enterprise with a code generated GUID ID as well as two contacts (Primary and Billing), assign the Enterprise ID to those and call SaveChanges on the TrackingState.Added object hierarchy (which at this point is Enterprise->Contacts->Addresses.
Without any Fluent mapping, EF Core 2.1 says.. "Both relationships between 'Contact' and 'Enterprise.BillingContact' and between 'Contact' and 'Enterprise.PrimaryContact' could use {'EnterpriseID'} as the foreign key. To resolve this configure the foreign key properties explicitly on at least one of the relationships."
I have attempted many configuratons and either wind up with a DB that only has one of the Contact properties in the Enterprise table defined, or the whole mess devolves into FK / cyclical hell.
Here are current class stubs..
public class Enterprise
{
public Guid ID {get; set;}
public Contact PrimaryContact {get; set;}
public Contact BillingContact {get; set;}
}
public class Contact
{
public Guid ID {get; set;}
public Guid EnterpriseID {get; set;}
public string FName {get; set;}
public string LName {get; set;}
public Address Address {get; set;}
}
public class Store
{
public Guid ID {get; set;}
public Guid EnterpriseID {get; set;}
public Contact PrimaryContact {get; set;}
}
public class Order
{
public Guid ID {get; set;}
public Guid EnterpriseID {get; set;}
public Guid StoreID {get; set;}
public Contact CustomerContact {get; set;}
}
public class Address
{
public Guid ID {get; set;}
public Guid EnterpriseID {get; set;}
public string Lines {get; set;}
}
I would really appreciate some advice on how to configure this.
The Enterprise table contains two Contacts, a PrimaryContact and a BillingContact.
Then the relationship among Enterprise, Contact and Address should be as follows:
public class Enterprise
{
[Key]
public Guid ID { get; set; }
public Guid PrimaryContactId { get; set; }
public Contact PrimaryContact { get; set; }
public Guid BillingContactId { get; set; }
public Contact BillingContact { get; set; }
}
public class Contact
{
[Key]
public Guid ID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public Address Address {get; set;}
}
public class Address
{
[Key]
public Guid ContactId {get; set;}
public string Lines {get; set;}
}
Then in the Fluent API configuration:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Enterprise>().HasOne(e => e.PrimaryContact)
.WithOne()
.HasForeignKey<Enterprise>(e => e.PrimaryContactId).OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Enterprise>().HasOne(e => e.BillingContact)
.WithOne()
.HasForeignKey<Enterprise>(e => e.BillingContactId).OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Contact>().HasOne(c => c.Address)
.WithOne().HasForeignKey<Address>(a => a.ContactId);
}

Table foreign key points to one of two tables

This is my first post so please excuse me if I didn't follow the correct procedure.
Also note that I have only started learning EF-Code First this week so I'm very new to it and don't really understand all the solutions on stackoverflow.
The problem:
I have three classes: User, Tenant and Dashboard.
A dashboard can only be for either a User or a Tenant.
In other words, a user has a dashboard and a tenant has a dashboard.
It is always a one-to-one relationship between User and Dashboard.
The same goes for Tenant and Dashboard.
How would one go about to create these relationships?
I have read through a lot of the data annotation methods as well as the fluent api methods but I have to admit am still dumbfounded as to how to get it going.
public class User
{
[Key]
public int ID { get; set; }
public int TenantId { get; set; }
public virtual Tenant Tenant { get; set; }
}
public class Tenant
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
public class Dashboard
{
[Key]
public int DashboardId { get; set; }
public string Description { get; set; }
}
In the following both Users and Tenants have a single dashboard
public class User
{
public int UserId {get; set;}
public virtual Dashboard Dashboard {get; set;}
}
public class Tenant
{
public int TenantId {get; set;}
public string Name {get; set;}
public virtual Dashboard Dashboard {get; set;}
}
public class Dashboard
{
public int DashboardId {get; set;}
public string Description {get; set;}
}

EF4.1 How to I implement a CascadeDelete where two tables share records in one table?

I'm using EF4.1 Code First. I have two classes which both have a one-to-one relationship with a contact class. When I remove a record in either of the two classes I want the associated entry in the contact class removed also.
ex:
public class User
{
public virtual int ID { get; set; }
...
public virtual Contact Contact { get; set; }
}
public class Admin
{
public virtual int ID { get; set; }
...
public virtual Contact Contact { get; set; }
}
public class Contact
{
public virtual int ID { get; set; }
...
}
I tried various things with annotations and fluent API but could not yet manage to get a cascade delete working. What is the correct way to implement this in EF 4.1 Code First?
I'm not sure but I think your contact entity needs User and Admin entities also..
Then the fluent api should work:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasRequired(u => u.Contact)
.WithRequiredPrincipal(c => c.User)
.WillCascadeOnDelete();
modelBuilder.Entity<Admin>()
.HasRequired(a => a.Contact)
.WithRequiredPrincipal(c => c.Admin)
.WillCascadeOnDelete();
}
I think this should work if you want to delete Users and Admins if a Contact is deleted:
public class User
{
public int ID { get; set; }
public int ContactId { get; set; }
public virtual Contact Contact { get; set; }
}
public class Contact
{
public int ID { get; set; }
public virtual List<User> Users {get; set;}
public Contact()
{
Users = new List<User>();
}
}
While I believe you want to do the opposite, which means you need to make the Contact is the dependent entity
public class User
{
public int ID { get; set; }
public bool IsAdmin {get; set;}
public virtual List<Contact> {get; set;}
public Contact()
{
Users = new List<User>();
}
}
public class Contact
{
public int ID { get; set; }
[ForiegnKey("Owner")]
public int UserId {get; set;}
public virtual User Owner {get; set;}
}
you can use other types of Inheritance other than TPC I'm using here, because DBMS doesn't support two mutually exclusive Foreign Keys