DESIGN TŁO:EF 6 - Kodeks pierwszy nieważne jeden-do-jednego relacji klucza obcego
Próbuję utworzyć kod pierwszego mapowania EF6 o następującej strukturze bazy danych:
projekt bazy danych jest następujące: Zamiast "ID klienta" jako klucza obcego we wszystkich powiązanych jednostkach (Zatrudnienie, wydatki, dochody itp.), mamy tabelę CustomerRelationship, która będzie zawierała identyfikator klienta, a następnie kolumnę "RelatedID", która będzie zawierał klucz powiązanej jednostki. Na przykład, powiedzmy, że mogę dodać rekord zatrudnienia dla CustomerID = 1, to stanie się co następuje:
Tworzenie rekordu w CustomerRelationship ustawienie CustomerID = 1 RelatedID = {nowy wygenerowany automatycznie EmploymentID, powiedzmy, 5} CustomerRelationshipTypeID = 55 (Id w tabeli przeglądowej, która stwierdza, że ten rekord jest typu zatrudnienia)
Tworzenie rekordu w tabeli zatrudnienia (EmploymentID = 5)
Powyższa struktura będzie działać dla wszystkich podmiotów powiązanych z Klientem.
mam mapowania współpracę na rzecz zatrudnienia, oto moje klasy:
public abstract class EntityBase : IEntity
{
#region IEntity Members
public int Id { get; set; }
public DateTime CreatedDate { get; set; }
public int CreatedUserId { get; set; }
public int CreatedSource { get; set; }
public DateTime ModifiedDate { get; set; }
public int ModifiedUserId { get; set; }
public int? DataMigrationId { get; set; }
public bool IsActive { get; set; }
#endregion
}
public class Employment : EntityBase
{
// ... all properties here.. removed most so easier to read
public int EmploymentTypeId { get; set; }
**public virtual ICollection<EmploymentRelationship> EmploymentRelationships { get; set; }**
}
public EmploymentMap()
{
this.HasKey(t => t.Id);
ToTable("tblEmployment");
Property(t => t.Id).HasColumnName("EmploymentID");
// Mapping for all properties follow
}
public abstract partial class CustomerRelationship : EntityBase
{
public int CustomerId { get; set; }
public decimal? PercentageShare { get; set; }
public int CustomerRelationshipTypeId { get; set; }
public int RelatedId { get; set; }
}
public class EmploymentRelationship : CustomerRelationship
{
public virtual Employment Employment { get; set; }
}
public EmploymentRelationshipMap()
{
this.HasKey(t => t.Id);
Map<EmploymentRelationship>(m =>
{
m.Requires("CustomerRelationshipTypeID").HasValue(55).IsRequired(); // Define lookup value for type of employment
m.ToTable("tblCustomerRelationship");
});
Property(t => t.Id).HasColumnName("CustomerRelationshipID");
Property(t => t.CustomerId).HasColumnName("CustomerID");
Property(t => t.RelatedId).HasColumnName("RelatedID");
HasRequired(t => t.Employment)
.WithMany(t => t.EmploymentRelationships)
.HasForeignKey(t => t.RelatedId);
}
public class Customer : EntityBase
{
// Customer Properties...
public Customer()
{
EmploymentRelationships = new List<EmploymentRelationship>();
}
public virtual ICollection<EmploymentRelationship> EmploymentRelationships { get; set; }
}
public CustomerMap()
{
this.HasKey(t => t.Id);
ToTable("tblCustomer");
Property(t => t.Id).HasColumnName("CustomerID");
}
public class CustomerContext
{
public CustomerContext()
: base(SymmetryCopy.context_connectionstring_main)
{
}
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<Employment> Employments { get; set; }
#region Customer Relationship entity mappings
public virtual DbSet<EmploymentRelationship> EmploymentRelationships { get; set; }
#endregion
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerMap());
modelBuilder.Configurations.Add(new EmploymentMap());
#region Customer Relationship entity mappings
modelBuilder.Configurations.Add(new EmploymentRelationshipMap());
#endregion
}
}
CustomerRepo do kontekstu kwerend i powrotu wyników:
public class CustomerRepository : BaseRepository<Customer, CustomerContext>, ICustomerRepository
{
public CustomerRepository() :
base(new CustomerContext())
{
}
public async Task<List<Employment>> GetEmployments(int customerId)
{
List<Employment> employments = new List<Employment>();
using (var context = new CustomerContext())
{
var employmentRelationships = context.EmploymentRelationships.Where(l => l.CustomerId == customerId).ToList();
employments = employmentRelationships.Select(x => x.Employment).ToList();
}
return employments;
}
}
Powyższa metoda GetEmployments następnie zwraca wszystkie rekordy identyfikujące CustomerID z CustomerRelingshipTypeID = 5 5 (Wartość kluczowa dla zatrudnienia). Zobacz powroty poniżej.
teraz, aby dostać się do moich rzeczywistych pytań:
Kiedy spróbować podłączyć inny podmiot typu, a mianowicie: koszt, zgodnie z tą samą podejścia jako że od zatrudnienia, tworzenie Expense.cs, ExpenseMap .cs, ExpenseRelationship.cs, ExpenseRelationshipMap.cs, posiadające następujące w ExpenseRElationshipMap.cs:
public class ExpenseRelationshipMap
{
public ExpenseRelationshipMap()
{
HasKey(t => t.Id);
Map<ExpenseRelationship>(m =>
{
m.Requires("CustomerRelationshipTypeID").HasValue(60).IsRequired();
m.ToTable("tblCustomerRelationship"); // Define lookup value for type of Expense
});
Property(t => t.Id).HasColumnName("CustomerRelationshipID");
Property(t => t.CustomerId).HasColumnName("CustomerID");
Property(t => t.RelatedId).HasColumnName("RelatedID");
Property(t => t.PercentageShare).HasColumnName("PercentageShare");
HasRequired(t => t.Expense)
.WithMany(t => t.ExpenseRelationships)
.HasForeignKey(t => t.RelatedId);
}
}
Raz Utworzono wpis Mapa, jak wykazano powyżej, gdy quering z GetEmployments() metodę, teraz pojawia się następujący exc eption:
„typów jednostki ExpenseRelationship 'i«EmploymentRelationship» nie mogą dzielić stół«tblCustomerRelationship», ponieważ nie są one w tej samej hierarchii typu lub nie posiada ważnej jeden do jednego klucza obcego relacji z pasujące klucze podstawowe między nimi. ",
Czego mi brakuje?
UPDATE
Zgodnie komentarzach jjj, I zostały zaktualizowane moje mapowania i stworzył klasę bazową CustomerRelationship.cs.
public class Employment : EntityBase
{
public string EmployerName { get; set; }
public string EmployerContactFirstName { get; set; }
public string EmployerContactSurname { get; set; }
public virtual ICollection<EmploymentRelationship> EmploymentRelationships { get; set; }
}
public class Expense : EntityBase
{
public string Description { get; set; }
public virtual ICollection<ExpenseRelationship> ExpenseRelationships { get; set; }
}
public abstract class CustomerRelationship : EntityBase
{
public int CustomerId { get; set; }
public int? CustomerRelationshipTypeId { get; set; }
public int RelatedId { get; set; }
}
public class EmploymentRelationship : CustomerRelationship
{
public virtual Employment Employment { get; set; }
}
public class ExpenseRelationship: CustomerRelationship
{
public virtual Expense Expense{ get; set; }
}
public class CustomerRelationshipMap : BaseMap<CustomerRelationship>
{
public CustomerRelationshipMap()
{
ToTable("CustomerRelationship");
Map<EmploymentRelationship>(m => m.Requires("CustomerRelationshipTypeID").HasValue(55));
Map<ExpenseRelationship>(m => m.Requires("CustomerRelationshipTypeID").HasValue(60));
Property(t => t.Id).HasColumnName("CustomerRelationshipID");
Property(t => t.CustomerId).HasColumnName("CustomerID");
Property(t => t.RelatedId).HasColumnName("RelatedID");
}
public class EmploymentRelationshipMap : BaseMap<EmploymentRelationship>
{
public EmploymentRelationshipMap()
{
HasRequired(t => t.Employment)
.WithMany(t => t.EmploymentRelationships)
.HasForeignKey(t => t.RelatedId);
}
}
public class ExpenseRelationshipMap : BaseMap<ExpenseRelationship>
{
public ExpenseRelationshipMap()
{
HasRequired(t => t.Expense)
.WithMany(t => t.ExpenseRelationships)
.HasForeignKey(t => t.RelatedId);
}
}
public class CustomerContext : BaseContext
{
public CustomerContext()
: base(context_connectionstring_main)
{
}
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<Employment> Employments { get; set; }
public virtual DbSet<CustomerRelationship> CustomerRelationships { get; set; }
public virtual DbSet<EmploymentRelationship> EmploymentRelationships { get; set; }
public virtual DbSet<ExpenseRelationship> ExpenseRelationships { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerMap());
modelBuilder.Configurations.Add(new EmploymentMap());
modelBuilder.Configurations.Add(new CustomerRelationshipMap());
modelBuilder.Configurations.Add(new EmploymentRelationshipMap());
modelBuilder.Configurations.Add(new ExpenseRelationshipMap());
}
}
Podczas kwerendy kontekst klienta tak:
var relationships = context.CustomerRelationships.Where(l => l.CustomerId == customerId).ToList();
otrzymuję następujący wyjątek:
„Komponent klucza obcego 'RelatedId' nie jest zadeklarowana nieruchomość na wpisz "EmploymentRelationship". Sprawdź, czy nie został jawnie wyłączony z modelu i czy jest to prawidłowa prymitywna właściwość. ",
Ok, to błąd ze składnikiem klucza obcego ma sens. Myślę, że nie można użyć właściwości klasy podstawowej dla powiązania klucza obcego klasy pochodnej. Zobacz http://stackoverflow.com/questions/11900155/how-to-map-foreign-keys-between-tph-tpt-objects-entity-framework-code-first i http://stackoverflow.com/questions/25619452/entity-framework-fluent-api-does-not-consider-base-class-properties – jjj
Używasz relacyjnej bazy danych. Dlaczego nie chcesz modelować relacji za pomocą relacji? – Colin