Multiple relationships to single table Entity Framework asp.net MVC - c#

I've just started using Entity Framework for my next project and I'm struggling with the following. I have the following ApplicationUser class:
public class ApplicationUser : IdentityUser
{
public string Name { get; set; }
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
}
I have two classes that inherent from this class:
public class TrainerUser : ApplicationUser
{
public virtual ICollection<ClientUser> Clients { get; set; }
}
public class ClientUser : ApplicationUser
{
public string TrainerId { get; set; }
public TrainerUser Trainer { get; set; }
}
The company class looks like this:
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<TrainerUser> Trainers { get; set; }
public virtual ICollection<ClientUser> Clients { get; set; }
}
What I can't figure out is how I can use the fluent API to not include 3 different companyId columns in the ApplicationUsers table.
Currently I have the following fluent API configuration:
modelBuilder.Entity<TrainerUser>().HasRequired(c => c.Company).WithMany(t => t.Trainers).HasForeignKey(c => c.CompanyId);
modelBuilder.Entity<ClientUser>().HasRequired(c => c.Company).WithMany(c => c.Clients).HasForeignKey(c => c.CompanyId);
Can anyone point me in the right direction?

Try adding these to your code.
modelBuilder.Entity<TrainerUser>().ToTable("TrainerUser");
modelBuilder.Entity<ClientUser>().ToTable("ClientUser");
If I am getting you right. you are trying to create a structure representing Table Per Hierarchy (TPT). Read more about it at the link.
Basically what happens is when entity framework encounters inheritance in the entities. Its Default attempt to create tables is by creating column of the set of all properties of all the derived entities from a class with a discriminator column.
What you are trying to create is a separate table for every class in the hierarchy.

Related

Map One-To-Many to 2 tables at the same time

I have 2 tables IncomingCheck and OutgoingCheck which contain many History items. To achieve this I've used inheritance and inherited 2 classes for incoming and outgoing histories.
public class IncomingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<IncomingCheckHistory> History { get; set; }
//... other stuff
}
public class OutgoingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<OutgoingCheckHistory> History { get; set; }
//... other stuff
}
public class CheckHistory
{
[Key]
public int Id { get; set; }
//... other stuff
}
public class IncomingCheckHistory : CheckHistory
{
public IncomingCheck IncomingCheck { get; set; }
}
public class OutgoingCheckHistory : CheckHistory
{
public OutgoingCheck OutgoingCheck { get; set; }
}
This approach works perfectly. In my database I have a table called CheckHistories with 2 nullable columns named [IncomingCheck_Id] and [OutgoingCheck_Id].
Now I have created a view on IncomingCheck which I created in Sql Server Management Studio and I can get its data using EF:
public class ViewIncomingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<IncomingCheckHistory> History { get; set; }
//... other stuff
}
So far so good, but now I want Entity Framework to automatically load the History items but when I try to load the data, I get the following error:
SqlException: Invalid column name 'ViewIncomingCheck_Id'.
Invalid column name 'ViewIncomingCheck_Id'.
My guess is that the EF is looking for a column named ViewIncomingCheck_Id in the IncomingCheckHistory table but can't find it.
Is there a way to tell EF that it should use IncomingCheck_Id instead of ViewIncomingCheck_Id?

How to configure one to many relationship along with inheritance in entityframework

I am working on entity framework code first pattern. I have one scenario where i have following entities,
public class Toy
{
public int ID {get; set;}
public string Name {get; set;}
}
for the above entity, all model building configuration has been done and table was created fine.
We have another entity,
public class Kid
{
public string Name {get; set;}
}
For this entity also, all model building configuration has been done and table was craeted fine in database.
Now i need to maintain/configure, one -many relationship between kid and toys i.e. one kid can have multiple toys
so i have create one custom class which will inherit Kid class,
public class KidToy : Kid
{
public virtual List<Toy> Toys{get; set;}
}
Note: I can't add List Toys property directly in Kid class, i am
getting circular refernce error.
builder.Entity<Kid>().Map<KidToy>(m => {
});
builder.Entity<KidToy>().HasMany(b => b.Toys).WithMany().Map(b =>
{
b.MapLeftKey(KidId");
b.MapRightKey("ToyId");
b.ToTable("kidToyMap");
});
I dont need table creation for the custom model class (KidToy) and i need to configure one-many relationship. Could you please guide me.
use this :
public class Toy
{
public int ID { get; set; }
public string Name { get; set; }
public int KidID { get; set; }
[ForeignKey("KidID")]
[InverseProperty("Toys")]
public virtual Kid Kid { get; set; }
}
public class Kid
{
public string Name { get; set; }
[InverseProperty("Kid")]
public virtual ICollection<Toy> Toys { get; set; }
}

Entity Framework Relationship Error

I get the following error when using Entity Framework:
Unable to determine the principal end of an association between the types
'xxx.Domain.Entities.UserSettings' and 'xxx.Domain.Entities.User'. The
principal end of this association must be explicitly configured using either
the relationship fluent API or data annotations.
Here are the two Entity classes:
public class User
{
[Key, Column("un")]
public string Username { get; set; }
public int Level { get; set; }
public virtual UserSettings UserSettings { get; set; }
}
public class UserSettings
{
[Key]
public string Username { get; set; }
public int ActiveRefresh { get; set; }
[ForeignKey("Username")]
public virtual User User { get; set; }
}
I am not sure how to resolve this error. I am stuck with the database design so I can't update that to fix the issue. Is there a way using Fluent Api to get these associations working?
A User can have a UserSettings object. This is the relationship that is desired.
It looks like you need a one to zero-or-one relationship
// Configure the primary key for the User
modelBuilder.Entity<User>()
.HasKey(t => t.Username);
// Map one-to-zero or one relationship
modelBuilder.Entity<UserSettings>()
.HasRequired(t => t.User)
.WithOptional(t => t.UserSettings);
This is not tested! Remove all the annotations from the entity classes. The link to Fluent API relationships in my comment above has more examples of the different kinds of relationship.
using anotations :
public class User
{
[Key, Column("un")]
public string Username { get; set; }
public int Level { get; set; }
//here is your foreign to UserSettings
public int? UserSettingsID{ get; set; }
[ForeignKey("UserSettingsID")] // not needed if you're using the '%ID' convention
//Navigation property
public virtual UserSettings UserSettings { get; set; }
}
public class UserSettings
{
//UserSettings PK
public int UserSettingsID{ get; set; }
public int ActiveRefresh { get; set; }
}
I assume here that you don't need to retrieve the user from his settings

EF5 Model-First, DBContext code generation and derived class

I'm creating a EF5 entity model with the designer (VS2012), and used the EF5 DbContext generator as code generation item.
My model contains an entity deriving from another (not abstract).
So let's say the base entity is called BaseEntity, and the derived entity is DerivedEntity.
Now I see in the generated context class, that there is no
Public DbSet<DerivedEntity> DerivedEntities { get; set; }
defined.
Only
Public DbSet<BaseEntity> BaseEntities { get; set; }
is defined.
Is this normal ? And if yes, how do I query the derived entities in linq ?
I'm used to query like this:
using(var ctx = new EntityContainer)
{
var q = from e in ctx.DerivedEntities <-- but this is now not possible since it doesn't exist
select e;
return q.ToList();
}
Thanks for replying.
EDIT:
As requested, generated classes posted:
public partial class Scheduling
{
public int Id { get; set; }
public string Subject { get; set; }
public System.DateTime BeginDate { get; set; }
public System.DateTime EndDate { get; set; }
}
public partial class TeamScheduling : Scheduling
{
public int TeamId { get; set; }
public Nullable<int> AssignmentId { get; set; }
public virtual Team Team { get; set; }
public virtual Assignment Assignment { get; set; }
}
public partial class EntityContainer : DbContext
{
public EntityContainer()
: base("name=EntityContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Team> Teams { get; set; }
public DbSet<Location> Locations { get; set; }
public DbSet<Country> Countries { get; set; }
public DbSet<Assignment> Assignments { get; set; }
public DbSet<ProductType> ProductTypes { get; set; }
public DbSet<AssignmentPreference> AssignmentPreferences { get; set; }
public DbSet<Scheduling> Schedulings { get; set; }
}
As you see, the EntityContainer class does not contain
public DbSet<TeamScheduling> TeamSchedulings { get; set; }
This is expected when you use inheritance the way you have. context.Schedulings contains both Scheduling objects and TeamScheduling objects. You can get the TeamScheduling objects only by asking for context.Schedulings.OfType<TeamScheduling>(). Note that you cannot meaningfully use context.Schedulings.OfType<Scheduling>() to get the others: that will also include the TeamScheduling objects.
You could alternatively try context.Set<TeamScheduling>(), but I'm not entirely sure that will work.
If your intention is to have two tables come up, say a parent Scheduling entity as well as a child TeamScheduling entity that has a foreign key back to the Scheduling entity, consider using a Table-per-Type (TPT) mapping as discussed here.
In essence, you should modify your "OnModelCreating" method to have the following code:
modelBuilder.Entity<TeamScheduling>().ToTable("TeamScheduling");
This explicitly tells EF that you want to have the TeamScheduling subclass to be represented as its own table. Querying it via LINQ would be simple as you would be able to do something like the following:
var teamScheds = context.Set<TeamScheduling>().Where(s => s.Id == 1).FirstOrDefault();

Relationship troubles with Entity Framework

I need help creating the relationship in entity framework as everything I have tried gives me errors when trying to add the migration or if I get passed that then I try to update the database and get an error about indexes with the same name.
public class Profile
{
public Profile()
{
Environments = new HashSet<Environment>();
}
[Key]
public int Id { get; set; }
public string VersionCreated { get; set; }
public string DiskLocation { get; set; }
public string Name { get; set; }
public DateTime DateTime { get; set; }
public virtual Product Product { get; set; }
public virtual Instance OriginalInstance { get; set; }
public virtual ICollection<Environment> Environments { get; set; }
}
public class Instance
{
public Instance()
{
TestResults = new HashSet<TestResult>();
Environments = new HashSet<Environment>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public string UserFriendlyName { get; set; }
public virtual Product Product { get; set; }
public virtual Profile LastKnownProfile { get; set; }
public virtual Computer Computer { get; set; }
public virtual ICollection<TestResult> TestResults { get; set; }
public virtual ICollection<Environment> Environments { get; set; }
}
The problem with the above classes is that the OrginalInstance property on the Profile class and the LastKnownProfile in the Instance class are supposed to just be foreign keys to those specific tables and they probably won't be the same very often. They can also both possibly be null.
I have tried:
modelBuilder.Entity<Instance>().HasRequired(i => i.LastKnownProfile);
modelBuilder.Entity<Profile>().HasRequired(p => p.OriginalInstance);
This gave me an Unable to determine the principal end of an association between the types 'EcuWeb.Data.Entities.Instance' and 'EcuWeb.Data.Entities.Profile'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations. error.
and with:
modelBuilder.Entity<Instance>().HasRequired(i => i.LastKnownProfile).WithOptional();
modelBuilder.Entity<Profile>().HasRequired(p => p.OriginalInstance).WithOptional();
The database adds a foreign key reference back to itself.
...that the OrginalInstance property on the Profile class and the
LastKnownProfile in the Instance class are supposed to just be foreign
keys to those specific tables and they probably won't be the same very
often. They can also both possibly be null.
In this case you actually want two one-to-many relationships between Profile and Instance if I don't misunderstand your quote above. It would mean that many Profiles can have the same OriginalInstance and that many Instances can have the same LastKnownProfile. The correct mapping would look like this then:
modelBuilder.Entity<Profile>()
.HasOptional(p => p.OriginalInstance)
.WithMany()
.Map(m => m.MapKey("OriginalInstanceId"));
modelBuilder.Entity<Instance>()
.HasOptional(i => i.LastKnownProfile)
.WithMany()
.Map(m => m.MapKey("LastKnownProfileId"));
The lines with MapKey are optional. Without them EF will create a foreign key with a default name.
Also note that you must use HasOptional (instead of HasRequired) if "both can possibly be null".

Categories