Table foreign key points to one of two tables - entity-framework

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

Related

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

Getting Error "The model backing the 'DBContext' context has changed since the database was created. "

I know This question is duplicate I found one solution too but this is four year old question and I think in these years the EntityFramework is on different level so I want to ask this question again. Here is the answer which I found and try to apply on entity Framework 5.0 but does not work
The model backing the <Database> context has changed since the database was created
here is my entity model classes first one is this
public class Student
{
public int StudentId {get; set;}
[StringLength(250),Required]
public string StudentName {get; set;}
[StringLength(20),Required]
public string Standard {get; set; }
[StringLength(250),Required]
public string Address {get; set; }
[StringLength(250),Required]
public string Emailid {get; set; }
[StringLength(12),Required]
public string Phoneno {get; set; }
}
and Second Model Class is this
public class Marks
{
public int MarksID { get; set; }
public int StudentId { get; set; }
public int English { get; set; }
public int Maths { get; set; }
public int Science { get; set; }
public int SocialStudy { get; set; }
public int Hindi { get; set; }
public int Total { get; set; }
public Student student { get; set; }
}
and this is my context class
public class DBContext:DbContext
{
public DBContext()
{
Database.SetInitializer<DbContext>(new DropCreateDatabaseAlways<DbContext>());
}
public DbSet<Student> TbStudent { get; set; }
public DbSet<Marks> TbMarks { get; set; }
}
I run this code and Getting this error
The model backing the 'DBContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
Please expert help me regarding this issue
Code first migration will help you resolving the case.But to proceed in your way to initialize the database you must replace DbContext with DBContext(i.e with your context class) in the Database.SetInitializer function like this.
public class DBContext:DbContext
{
public DBContext()
{
Database.SetInitializer<DBContext>(new DropCreateDatabaseAlways<DBContext>());
}
}
Hope this helps.

updating an entity needs re-making relations in ef?

I am using ef 4.1 in my application and I have entities like below:
public partial class Role
{
[Key]
public int Id { get; set; }
[StringLength(20)]
[Required()]
public string RoleTitle { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public partial class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long UserId { get; set; }
[StringLength(20)]
[Required()]
public string UserName { get; set; }
public bool Status { get; set; }
[Required()]
public virtual Role Role { get; set; }
}
is it true that every time I want to update some field of User entity, say Status, I should re0make it is relations ?
Cause when I want to update only status field and save changes (I use Unit of Work), it throws and says "The Role field is required."...
No, you don't have to remake its relations. You also shouldn't be putting the Required annotation on the virtual property. You should be putting it on the ForeignKey ID field for the Role table. I believe you're getting the error because it's never setting the Role correctly on the User class in the first place, which is why you keep having to remake it.
To illustrate, here's what your User class should look like:
public partial class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public long UserId { get; set; }
[StringLength(20)]
[Required]
public string UserName { get; set; }
[Required, ForeignKey("Role")]
public int RoleID { get; set; }
public bool Status { get; set; }
public virtual Role Role { get; set; }
}

EF 4 Code First - How do I model this?

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.

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