Entity framework Unidirectional Association One to Many - entity-framework

I'm new in Entity Framework and my English is not very good, sorry if i write something wrong. I want to make an unidirectional association in One-to-Many relationship with Entity Framework 6 using the following example:
public class Person
{
public int personId;
public string Name;
.
.
.
//public ICollection<Phone> Phones { get; set; } //I don't want this nav property
}
public class Phone
{
public int phoneId;
public string number;
public Person myPerson { get; set; }
}
In this classes, a Person has many Phone, so a Phone has only a Person (1 to 1...*) but I want to create the navigation property in Phone, not in Person.
How to create this association with Fluent API for mappings?

Use following mapping
modelBuilder.Entity<Phone>().HasRequired(p => p.myPerson).WithMany();
HasRequired configures required relationship for phone (i.e. it's required to have person id)
WithMany() configures relationship to be required:many without navigation property on many side
Consider reading Configuring Relationships with the Fluent API article.

First of all, you need to be more clear on what you want, considering you changed your question in Sergey's answer.
Considering it, this is what your classes will look like (yes, navigation properties inheritance is supported):
public class Person
{
public int personId { get; set; }
public string Name { get; set; }
}
public abstract class Phone
{
public int phoneId { get; set; }
public int personId { get; set; }
public Person myPerson { get; set; }
}
public class PhoneFixedLine : Phone
{ }
public class PhoneCellPhone : Phone
{ }
Obs.: Mind the getters and setters in the Person and Phone classes.
You want an unidirectional mapping with the navigation property in the Phone class.
Since you are mapping derivated classes you need to follow an Inheritance Strategy, see this linkfor more information.
I will be following the TPC strategy where only the concrete classes are mapped.
In the OnModelCreatingMethod do the following:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<PhoneFixedLine>().HasRequired(p => p.myPerson).WithMany()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("FixedPhones");
});
modelBuilder.Entity<PhoneCellPhones>().HasRequired(p => p.myPerson).WithMany()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("CellPhones");
});
}
You will face an identity problem with this strategy because these two table share the same primary key phoneId, in the link of the Inheritance Strategies there are two ways of dealing with it.

Related

Configuring one-to-many and one-to-one relationship in Entity Framework Core

I'm quite new to Entity Framework and am picking it up with the Core version.
I'm trying to understand how to customise model relationships.
My basic model is that I have a Company entity, and a Contact entity. A Company can have many Contacts. A company can a KeyContact, which must be one of the associated contacts, but is not required.
Thus there is a One to Many relationship, but also a One to One relationship. I've tried to implement this as below (removed most other fields for clarity);
public class Company
{
public int Id { get; set; }
public int? KeyContactId { get; set; }
public ICollection<Contact> Contacts { get; set; }
public Contact KeyContact { get; set; }
}
public class Contact
{
public int Id { get; set; }
public int CompanyId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Company Company { get; set; }
}
It fails to add this migration with the message;
Unable to determine the relationship represented by navigation property 'Company.Contacts' of type 'ICollection'. Either manually configure the relationship, or ignore this property from the model.
I can kinda see why it's complaining about this, but I'm not sure if there's a way with the model builder I can configure this, or whether it's an invalid pattern. My model builder is currently just basic;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Company>().ToTable("Company");
modelBuilder.Entity<Contact>().ToTable("Contact");
}
I know I could just have a flag to say IsKeyContact in the contact table, but I like the idea of having the navigation property in the company entity. So I'm wondering how sugary Entity can be.
Any help much appreciated.
Thanks,
Nick
The exception is avoided by adding the following line to the OnModelCreating method:
modelBuilder.Entity<Company>().HasMany(p => p.Contacts).WithOne(d => d.Company).HasForeignKey(d => d.CompanyId);
This configures the Company.Contacts-Contact.Company relation. By default, the Company.KeyContact relation is configured as if the following line would be within the OnModelCreating method:
modelBuilder.Entity<Company>().HasOne(e => e.KeyContact).WithMany().HasForeignKey(e => e.KeyContactId);
Hence a Contact can be the KeyContact of more than one Company.
In order to ensure that a Contact can be the KeyContact of at most one Company the Company.KeyContact relation could be configured by the following line within the OnModelCreating method:
modelBuilder.Entity<Company>().HasOne(e => e.KeyContact).WithOne().HasForeignKey<Company>(e => e.KeyContactId);
But note: This will not ensure that the KeyContact is a member of the Contacts.

Is it possible define one-to-many relation in Sql Server and just define and use one side of this relation in entity code first

If I defined one-to-many relation foreign-key constraints in Sql Server, Is it possible just define and use it in code-first class definitions in one side?
For example suppose I have Library and Book classes. Each Library can has many books but each book belong to one library.
public class Book
{
public Book() { }
public int BookId { get; set; }
public string BookName { get; set; }
public virtual Library Library { get; set; }
}
public class Library
{
public Library() { }
public int LibraryId { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
If I want always just use this relation from Book side,Can I don't define below line in Library class definition?
public virtual ICollection<Book> Books { get; set; }
Sure, you can do this:
modelBuilder.Entity<Book>()
.HasRequired(b => b.Library) // Or: HasOptional
.WithMany()
.Map(m => m.MapKey("LibraryId"))
In this case, the database table Book has foreign key field LibraryId that's either required or optional (nullable). The foreign key is not mapped to a property in class Book. This is called an independent association.
You can also map the key to a property in Book if you want:
modelBuilder.Entity<Book>()
.HasRequired(b => b.Library)
.WithMany()
.HasForeignKey(b => b.LibraryId))
This turns the association into a foreign key association. In many cases this can be beneficial.

Will one-to-one foreign key associations be supported in EF v-Next?

I have entities A and B and I want to create 2 distinct 1-1 associations between A and B. A should play the role as principal. Like this:
public class A
{
public int Id {get; set;}
public B B1 {get; set;}
public B B2 {get; set;}
}
public class B
{
public int Id {get; set;}
}
Since EF does not support one-to-one foreign key associations I cannot create a working model/database with EF. To my this sounds like a serious limitation. Are there any plans to support such associations in an upcoming version of EF?
What is the best workaround for to get this working. I know about creating two one-2-many associations. However, that would make B the principal and gives me problems with cascading deletes.
Thanks for replying to my question. Below is an example of what I want to do, i.e., create two (or more) 1-to-1 associations between an entity A and another entity B. Is this something that EF could support in vNext, or else, why would it be a bad idea?
Thanks again,
Merijn
public class A
{
public int Id {get; set;}
public int B1_Id {get; set;}
public B B1 {get; set;}
public int B2_Id {get; set;}
public B B2 {get; set;}
}
public class B
{
public int Id {get; set;}
}
public class SampleContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<A>().HasKey(c => c.Id);
modelBuilder.Entity<B>().HasKey(c => c.Id);
modelBuilder.Entity<A>().HasRequired(c => c.B1).WihOptional().ForeignKey(x=>x.B1_Id);
modelBuilder.Entity<A>().HasRequired(c => c.B2).WihOptional().ForeignKey(x=>x.B2_Id);
}
}
If "v-Next" is Entity Framework 6, then no, it apparently won't support one-to-one foreign key associations, as you can see on the roadmap for all features planned for EF 6.
You can also see that Unique Constraint support is not on the roadmap and still marked as "Under Review" on UserVoice.
Because a one-to-one foreign key association is basically a one-to-many association with a unique constraint on the foreign key column I would expect that one-to-one FK associations won't be implemented before Unique Constraint support is available. It's especially required if you want that A is the principal in your two relationships. Currently EF does not support relationships where the principal's key is not the primary key but some column with unique constraint.
In this blog post the feature is described and mentioned that it is "postponed", so let's hope for EF 7.
Perhaps it is a terminology issue.
In Code first EF, EF doesnt allow you to have 1:1 relationships with Principal and Dependent both with foreign keys to each other
or with the dependent having its own primary key unrelated to Principal.
With your example it looks like that it is a case of 2 navigation properties required.
And strictly speaking it is not 1:1. since you have 2 relationships to the same table.
you have 2 relationships of type 1:1.. EF sees this as many to 1.
If you have a true 1:1 relationship, EF will want the dependent to have the same Primary Key as the primary.
You can define Multiple NAVIGATION properties on Both Principle and dependent, which result in indexes.
So you may wish to investigate Many to 1 configurations
If you want the Primary to have an OPTINAL Foreign Key at DB level, You would need to ADD this FK later during migration or with script.
But arguably this is best seen as business logic/rule check rather than an OPTIONAL FK on principal.
So yes there are limitations in matching exactly what is possible on the DB.
But it is questionable is actually necessary in a code first scenario.
Neat trick here btw is to model in DB exactly what you want on Code first.
There use the EF Powertool nuget to reerse engineer Codefirst from DB.
EG mini DB with just the desired table relationships.
make a new project in Solution. Install Entity Framework Powertools.
Then use right click option in new project to "reverse engineer code first from DB".
It shows how to build that in code first if it can.... :-)
What I think you wanted to achieve... see code sample (sorry if I misunderstood the point your are making) code should execute if NUGET is loaded
using System.Data.Entity;
namespace EF_DEMO
{
class FK121
{
public static void ENTRYfk121(string[] args)
{
var ctx = new Context121();
ctx.Database.Create();
System.Console.ReadKey();
}
}
public class Main
{
public int MainId { get; set; }
public string BlaMain { set; get; }
public int? Sub1Id { set; get; } // Must be nullable since we want to use EF foreign key
public int? Sub2Id { set; get; } // Must be nullable since we want to use EF foreign key
public virtual Sub Sub1 { get; set; } // Reverse navigation
public virtual Sub Sub2 { get; set; } // Reverse navigation
// you may also need
public virtual ICollection<Sub> Subs { get; set; }
}
public class Sub
{
public int SubId { get; set; } // Deliberately DIFFERENT KEY TO MAIN.... not 1:1 so this is possible
public string blasub { set; get; }
public int MainId { set; get; } //set in API , this the FK
public virtual Main Main { get; set; } // van to Principal
}
public class Context121 : DbContext
{
static Context121()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context121>());
}
public Context121()
: base("Name=Demo") { } // webconfig required to match
public DbSet<Main> Mains { get; set; }
public DbSet<Sub> Subs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Main>().HasKey(t => t.MainId)
.HasOptional(t => t.Sub1)
.WithMany()
.HasForeignKey(t=>t.Sub1Id) ; // tell EF the field is in POCO, use this please, otherwise it will create it.
modelBuilder.Entity<Main>()
.HasOptional(t => t.Sub2).WithMany()
.HasForeignKey(t=>t.Sub2Id);
modelBuilder.Entity<Sub>()
.HasKey(t => t.SubId)
.HasRequired(q => q.Main)
.WithMany()
.HasForeignKey(t => t.MainId);
}
}
}
WEBCONFIG....
<connectionStrings>
<add name="Demo" connectionString="Data Source=localhost;Initial Catalog=Demo;Integrated Security=True;MultipleActiveResultSets=True;App=EntityFramework"
providerName="System.Data.SqlClient" />
</connectionStrings>
Explain what problem do you need to resolve? This is sample of one-to-one mapping in EF 5.0
class Program
{
static void Main(string[] args)
{
using (var context = new SampleContext())
{
var mainEntity = new MainEntity();
mainEntity.DetailEntity = new DetailEntity();
context.SaveChanges();
}
}
}
public class SampleContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MainEntity>().HasKey(c => c.Id);
modelBuilder.Entity<DetailEntity>().HasKey(c => c.Id);
modelBuilder.Entity<MainEntity>().HasOptional(c => c.DetailEntity).WithRequired(p => p.MainEntity);
modelBuilder.Entity<DetailEntity>().HasRequired(c => c.MainEntity).WithOptional(p => p.DetailEntity);
}
public virtual DbSet<MainEntity> MainEntities { get; set; }
public virtual DbSet<DetailEntity> DetailEntities { get; set; }
}
public class MainEntity
{
public int Id { get; set; }
public DetailEntity DetailEntity { get; set; }
}
public class DetailEntity
{
public int Id { get; set; }
public MainEntity MainEntity { get; set; }
}

Entity Framework TPH Inheritance Data Modeling Issues

I'm new to Entity Framework and C#/.Net and trying to create a TPH inheritance model, I'm not sure if I should be or not, so if not, please advise,
Here's the model:
public abstract class Vote
{
public int VoteID { get; set; }
public int UserID { get; set; }
public bool Value { get; set; }
public DateTime DateCreated { get; set; }
public User User { get; set; }
}
public class ProjectVote_ : Vote
{
public int ProjectID { get; set; }
public virtual Project Project { get; set; }
}
public class CommentVote_ : Vote //There are three more like this, votes for different hings
{
public int CommentID { get; set; }
public virtual Comment Comment { get; set; }
}
Now the Project model (comment and model is similar)
public class Project
{
public int ProjectID { get; set; }
public string Title { get; set; }
public virtual ICollection<Vote> Vote { get; set; }
}
What happens is that ICollection creates a database column Project_ProjectID as the foreign key in the Vote table (I think) instead of using the ProjectID I defined. How do I fix it or should I model it differently. If the fluent API is the way to fix it, I don't know how to do that.
In the end I want to be able to use one table to store 5 different types of votes.
When you have related entities you don't need to have a property to store the FK in your model. Entity framework knows that it needs to make a FK to the Project table in ProjectVote when it detects Project in your ProjectVote_ model. Same thing with User and UserId and Comment and CommentId. You don't need to have a property that stores the FK in your model.
You are getting the FK column with the name you don't like "Project_ProjectID" because Entity framework is detecting that it needs to create a FK for your navigation property "Project". It's using it's own naming convention to create the column hence "Project_ProjectID".
If you want to provide your own name for the column override OnModelCreating in your DBContext class and add this fluent mapping.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Project>()
.HasMany(p => p.Vote)
.HasRequired(v => v.Project) //or .WithOptional(v => v.Project)
.Map(m => m.MapKey("ProjectId")); //or any other name you want.
}
And for the future this is a helpful reference for how to use the Fluent API. For example here is some documentation on how to custimize TPH with fluent.
Hope that helps!

Can Fluent NHibernate's AutoMapper handle Interface types?

I typed this simplified example without the benefit of an IDE so forgive any syntax errors. When I try to automap this I get a FluentConfigurationException when I attempt to compile the mappings -
"Association references unmapped class
IEmployee."
I imagine if I were to resolve this I'd get a similar error when it encounters the reference to IEmployer as well. I'm not opposed to creating a ClassMap manually but I prefer AutoMapper doing it instead.
public interface IEmployer
{
int Id{ get; set; }
IList<IEmployee> Employees { get; set; }
}
public class Employer: IEmployer
{
public int Id{ get; set; }
public IList<IEmployer> Employees { get; set; }
public Employer()
{
Employees = new List<IEmployee>();
}
}
public interface IEmployee
{
int Id { get; set; }
IEmployer Employer { get; set; }
}
public class Employee: IEmployee
{
public int Id { get; set;}
public IEmployer Employer { get; set;}
public Employee(IEmployer employer)
{
Employer = employer;
}
}
I've tried using .IncludeBase<IEmployee>() but to no avail. It acts like I never called IncludeBase at all.
Is the only solution to either not use interfaces in my domain entities or fall back on a manually defined ClassMap?
Either option creates a significant problem with the way my application is designed. I ignored persistence until I had finished implementing all the features, a mistake I won't be repeating again :-(
It's not a restriction imposed by Fluent or its AutoMapper, but by NHibernate itself.
I therefore don't think you'd get there with the manual class map. You'll have to lose the interfaces in the property and list definitions. You can keep the interfaces, but mapped properties and collections must use the concrete types of which NHibernate knows.
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.Id);
Map<Address>(x => x.Address); // Person.Address is of type IAddress implemented by Address
}
}