Reputation: 3001
I've found some similar questions here, but none were aswered with something that would work for me.
I have a project with about 60 entities with lots of scenarios, all mapped to the database by the simple use of some basic EF annotations. One scenario that I couldn't put to work, is the following:
public class Client {
[Key]
public int IDClient { get; set; }
(...)
}
public class Research {
[Key]
public int IDReasearch { get; set; }
(...)
}
public class ClientReaserach {
[Key, Column(Order = 1)]
public int IDClient { get; set; }
[ForeignKey("IDClient")]
public virtual Client Client { get; set; }
[Key, Column(Order = 2)]
public int IDResearch { get; set; }
[ForeignKey("IDResearch")]
public virtual Research Research { get; set; }
(...)
}
Although this seems like other scenarios that worked so far, this one seems to me like a fluentAPI kind of thing (as far as I know, annotations only gives me a sub-set of EF's real capacities).
So I have some questions:
Can I remain using my annotations and use fluentAPI to map only the situation described above?
How will EF "knows" that this entities and its relationships are mapped through the fluentAPI (and not try to map them again when I add a new migration)?
Is it OK to rebuild all my project using fluentAPI? What should I do withh all the migrations already generated (should I just delete them)?
How would I accomplish the above scenario through fluentAPI?
EDIT 1:
This is the real code that I'm using to accomplish the scenario mentioned, is the following:
public class PacientePesquisa
{
[Key, Column(Order = 1)]
[Required(ErrorMessage = Msg_Critica_Req_IDPesquisa)]
[Display(Name = "Pesquisa")]
public int IDPesquisa { get; set; }
[ForeignKey("IDPesquisa")]
public virtual Pesquisa Pesquisa { get; set; }
[Key, Column(Order = 2)]
[Required(ErrorMessage = Msg_Critica_Req_NRProntuario)]
[StringLength(NRProntuario_MaxLength, ErrorMessage = Msg_Critica_Tam_NRProntuario)]
[Display(Name = "Prontuário")]
public string NRProntuario { get; set; }
[ForeignKey("NRProntuario")]
public virtual Paciente Paciente { get; set; }
(...)
public class Pesquisa
{
[Key]
public int IDPesquisa { get; set; }
(...)
public class Paciente
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string NRProntuario { get; set; }
(...)
And when running the "add-migration", I'm receiving the following error:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:
System.Data.Entity.Edm.EdmAssociationConstraint: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.
Upvotes: 1
Views: 117
Reputation: 177133
I'll try to answer your questions, but one question up front: What is the problem with your mapping with annotations? It looks fine to me and I don't see a need for Fluent API. In this answer is a similar model ("many-to-many relationship with payload") and it uses annotations and mapping conventions exclusively without any Fluent API mapping.
About your questions:
Can I remain using my annotations and use fluentAPI to map only the situation described above?
Yes, you can mix mapping via data annotations and via Fluent API without problems - as long as you don't create contradicting mappings, like renaming a column with annotations to a different name than with Fluent API.
How will EF "knows" that this entities and its relationships are mapped through the fluentAPI (and not try to map them again when I add a new migration)?
EF processes the OnModelCreating
method of your context and applies the mapping you have defined. It also processes the annotations and applies the mappings defined there. It merges both mappings to a single model. This model is serialized to a "model hash" that is stored in the MigrationHistory
table in your database. If the model hash is identical with the latest already stored hash value EF knows that model and database are in sync and up-to-date and doesn't create a new migration.
Is it OK to rebuild all my project using fluentAPI? What should I do withh all the migrations already generated (should I just delete them)?
Yes, it's OK. There is no need to delete the old migrations. Adding a new mapping with Fluent API is just a new evolution of your entity model - like adding new annotations is.
How would I accomplish the above scenario through fluentAPI?
modelBuilder.Entity<ClientResearch>()
.HasKey(cr => new { cr.IDClient, cr.IDResearch });
modelBuilder.Entity<ClientResearch>()
.HasRequired(cr => cr.Client)
.WithMany() // or .WithMany(c => c.ClientResearches) if you have a collection
.HasForeignKey(cr => cr.IDClient);
modelBuilder.Entity<ClientResearch>()
.HasRequired(cr => cr.Research)
.WithMany() // or .WithMany(r => r.ClientResearches) if you have a collection
.HasForeignKey(cr => cr.IDResearch);
Upvotes: 2