EntityFramework navigation property not working as expected - c#

I have the following 3 (simplified) classes setup in entity framework
public class Service
{
[Key]
public int ServiceId { get; set; }
public int WorkformId { get; set; }
[ForeignKey("WorkformId")]
public virtual Workform Workform { get; set; }
}
public class Workform
{
[Key]
public int WorkformId { get; set; }
[ForeignKey("WorkformId")]
public virtual ICollection<FieldMap> FieldMaps { get; set; }
}
public class FieldMap
{
[Key]
public int FieldMapId{ get; set; }
public int WorkformId{ get; set; }
}
And if I try to do something like this
var service = db.Services.Include("Workform.FieldMaps")
.FirstOrDefault(p => p.ServiceId == serviceId);
service.Workform.FieldMaps is pulling the entire collection, not just the records with the matching relational id.
Am I missing some here?

Related

Entity Framework Core One-to-One, Not Unique

Given two tables, TrackingTag and TrackingTagStatusUpdate:
public class TrackingTag
{
public int ID { get; set; }
}
public class TrackingTagStatusUpdate
{
public int ID { get; set; }
public int TrackingTagID { get; set; }
public TrackingTag TrackingTag { get; set; }
public int Epoch { get; set; } //32-bit
[MaxLength(32)]
public string APConnectedSSID { get; set; }
}
As there will be many TrackingTagStatusUpdates, I want to add a field "LatestStatusUpdate" to TrackingTag, for performance reasons.
public class TrackingTag
{
public int ID { get; set; }
public int? LatestStatusUpdateID { get; set; }
public TrackingTagStatusUpdate LatestStatusUpdate { get; set; }
}
LatestStatusUpdate is optional, as it may not be set if there are not yet any Status Updates for the Tag.
Entity Framework Core complains that "The child/dependent side could not be determined for the one-to-one relationship between 'TrackingTag.LatestStatusUpdate' and 'TrackingTagStatusUpdate.TrackingTag'.". I then add
modelBuilder.Entity<TrackingTag>().HasOne(x => x.LatestStatusUpdate).WithOne(x => x.TrackingTag).HasForeignKey<TrackingTagStatusUpdate>(x => x.TrackingTagID);
to OnModelCreating(ModelBuilder modelBuilder), however this results in Entity Framework Core creating a relationship with a Unique constraint, which will not work as there will be many TrackingTagStatusUpdate with the same TrackingTagID.
How do I do this correctly?
This seems to have worked:
public class TrackingTag
{
public int ID { get; set; }
[ForeignKey(nameof(LatestStatusUpdate))]
public int? LatestStatusUpdateID { get; set; }
public TrackingTagStatusUpdate LatestStatusUpdate { get; set; }
}
I'm not sure how to achieve the same with the Fluent API though.

CodeFirst EF Core - Implementing interfaces possible?

I'm a little new to code-first in EF Core and I'm trying a few things out and I'm a little confused how to implement the below (or indeed whether it can be implemented or not).
In my model I have a class that maps entities to cases, with the following mapping class
public class CaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CaseEntityId { get; set; }
public int CaseId { get; set; }
public CaseModel Case { get; set; }
public Guid EntityId { get; set; }
public EntityModel Entity { get; set; }
}
I am now implementing the EntityModel object. However an entity can be either a Person or a Company. Both these have common properties, but there are some natural differences. What I wanted to do is create an IEntityModel interface and two classes as below
public class CaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CaseEntityId { get; set; }
public int CaseId { get; set; }
public CaseModel Case { get; set; }
public Guid EntityId { get; set; }
public IEntityModel Entity { get; set; }
}
public interface IEntityModel
{
Guid EntityId { get; set; }
PostalAddress PrincipalAddress { get; set; }
}
public class CompanyEntity : IEntityModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid EntityId { get; set; }
public string CompanyName { get; set; }
public PostalAddress PrincipalAddress { get; set; }
}
public class PersonEntity : IEntityModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid EntityId { get; set; }
public PostalAddress PrincipalAddress { get; set; }
public string FirstNames { get; set; }
public string Surname { get; set; }
}
When I try to build this I get the error
The property 'CaseEntity.Entity' is of an interface type ('IEntityModel'). If it is a navigation, manually configure the relationship for this property by casting it to a mapped entity type.
Otherwise, ignore the property using the [NotMapped] attribute or 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I'm not 100% certain I can do what I'm trying to do. Searching around has left me a little confused (is that a solution to implement kind of functionality like, or should I use implement an entity class that has all the properties need to support a Company or a Person?)
I think it would be better if you create a base class
public class EntityModel:IEntityModel
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int EntityId { get; set; }
publlic PostalAddress PrincipalAddress { get; set; }
}
CompanyEntity
public class CompanyEntity : EntityModel
{
public string CompanyName { get; set; }
}
CaseEntity
public class CaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CaseEntityId { get; set; }
public int CaseId { get; set; }
public CaseModel Case { get; set; }
public int EntityId { get; set; }
public virtual EntityModel EntityModel { get; set; }
}

How do I set up a one-to-many relationship using Entity Framework Core?

I'm working on a trucking API using Entity Framework (EF) Core. Basic CRUD operations are working fine using the repository pattern. There is an error in
configurations I am implementing, however.
I want to obtain multiple trailers and trucks associated with single load, reflecting the one-to-many relationship.
public class LoadConfiguration : IEntityTypeConfiguration<Load>
{
public void Configure(Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder<Load> builder)
{
builder.Property(p=>p.Id).IsRequired();
builder.HasOne(t=>t.Customer).WithMany().HasForeignKey(p=>p.CustomerId);
builder.Property(p=>p.LoadedFrom).IsRequired();
builder.HasMany(p=>p.Trailer).WithOne().HasForeignKey(t=>t.TrailerId);
builder.HasMany(p=>p.Truck).WithOne().HasForeignKey(t=>t.TruckId);
builder.Property(p=>p.Destination).IsRequired();
}
}
public class Truck:BaseEntity
{
public int PlateNo { get; set; }
public string ModelName { get; set; }
public Location StateCode { get; set; }
public int PollutionCertificateValidity { get; set; }
public int DateOfPurchase { get; set; }
public int FitnessCertificateValidity { get; set; }
}
public class Load:BaseEntity
{
public Customer Customer { get; set; }
public int CustomerId { get; set; }
public string LoadedFrom { get; set; }
public Trailer Trailer { get; set; }
public int TrailerId { get; set; }
public Truck Truck { get; set; }
public int TruckId { get; set; }
public string Destination { get; set; }
}
public class Trailer:BaseEntity
{
public int TrailerCapacity { get; set; }
public Truck Truck { get; set; }
public int TruckId { get; set; }
}
public class BaseEntity
{
public int Id { get; set; }
}
A one-to-many relationship is defined by using navigation collections, that has the capacity to hold many Trucks and Trailers. You can choose the collection type freely, but I would suggest ICollection generic type.
Modify your Load class as follows:
public class Load:BaseEntity
{
public Customer Customer { get; set; }
public int CustomerId { get; set; }
public string LoadedFrom { get; set; }
public string Destination { get; set; }
// navigation collections
public ICollection<Trailer> Trailers { get; set; }
public ICollection<Truck> Trucks { get; set; }
}
You will then be able to set up the relationship in your LoadConfiguration class by using
the pluralized name:
builder.HasMany(p=>p.Trailers).WithOne();
builder.HasMany(p=>p.Trucks).WithOne();
.. even though EF Core will be smart enough to figure out the relation by convention so the fluent configuration is redundant.

Custom one-to-many relationship in EF 6.1

Is it possible to write custom logic for a one-to-many relationship? Suppose I have the following classes:
public class ProductIncompatibility
{
[Key]
public int ProductIncompatibilityId { get; set; }
public int ProductIdA { get; set; }
public int ProductIdB { get; set; }
[ForeignKey("ProductIdA")]
public virtual Product ProductA { get; set; }
[ForeignKey("ProductIdB")]
public virtual Product ProductB { get; set; }
}
public class Product
{
[Key]
public int ProductId { get; set; }
public virtual ICollection<ProductIncompatibility> IncompatibleProducts { get; set; }
}
When I execute the following Linq-query:
Products.Select(it => new { it.ProductId, it.IncompatibleProducts })
or
Products.Include("IncompatibleProducts")
I would expect all ProductIncompatibility-records where ProductIdA = ProductId || ProductIdB = ProductId.
Is it possible to specify this logic, for example using the modelBuilder?

Entity framework with many one-to-zero-or-one relationships

I want to implement many one-to-zero-or-one relationships in one entity, but I am having problems getting it to work then generating the migration for it.
public class Invoice
{
public int Id { get; set; }
public int? MorningExpenseId { get; set; }
public int? EveningExpenseId { get; set; }
public Expense MorningExpense { get; set; }
public Expense EveningExpense { get; set; }
}
public class Expense
{
public int Id { get; set; }
public int InvoiceId { get; set; }
public Invoice Invoice { get; set; }
}
modelBuilder.Entity<Invoice>()
.HasOptional<Expense>(p => p.MorningExpense)
.WithRequired(g => g.Invoice);
modelBuilder.Entity<Invoice>()
.HasOptional<Expense>(p => p.EveningExpense)
.WithRequired(g => g.Invoice);
But I am getting an error of Schema specified is not valid. Errors: The relationship '...' was not loaded because the type '...' is not available..
I also was experimenting with using a primary composite key in the ´Expense´ class like:
public enum ExpenseType { Morning, Evening };
public class Expense
{
public int Id { get; set; }
public ExpenseType ExpenseType { get; set; }
public Invoice Invoice { get; set; }
}
But also no luck with getting it to work. How this should be implemented using Fluent API?
In Entity framework, appliation types must match Database types. Relationships must have the virtual keywork.
You must code like this
public class Invoice
{
public int Id { get; set; }
public int MorningExpenseId { get; set; }
public int EveningExpenseId { get; set; }
public virtual Expense MorningExpense { get; set; }
public virtual Expense EveningExpense { get; set; }
}
public class Expense
{
public int Id { get; set; }
public int InvoiceId { get; set; }
public virtual Invoice Invoice { get; set; }
}

Categories