How can I build a model using Entity Framework to join 3 tables?
At the moment I have:
public class KeywordAdCategory
{
[Key]
[Column("Keyword_Id", Order = 0)]
public int Keyword_Id { get; set; }
[Key]
[Column("Ad_Id", Order = 1)]
public int Ad_Id { get; set; }
[Key]
[Column("Category_Id", Order = 2)]
public int Category_Id { get; set; }
}
But I don't have any navigation properties.
Is there a better way to build a relashionship between 3 tables using Entity Framework?
Also the Keyword, Ad and Category models:
public class Keyword
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public class Ad
{
// Primary properties
[Key]
public int Id { get; set; }
// Navigation properties
public AdOperation AdOperation { get; set; }
public Member Member { get; set; }
public Address Address { get; set; }
public Category Category { get; set; }
public virtual ICollection<Picture> Pictures { get; set; }
private ICollection<Feature> _features;
public virtual ICollection<Feature> Features
{
get { return _features ?? (_features = new HashSet<Feature>()); }
set { _features = value; }
}
}
public class Category
{
// Primary properties
public int Id { get; set; }
public int? CategoryParent_Id { get; set; }
public int? CategoryGroup_Id { get; set; }
public bool IsActive { get; set; }
// Navigation properties
public Keyword Keyword { get; set; }
}
Thanks.
I'm assuming that you're using Code-First Entity Framework here, and that you have your KeywordAdCategory object in your database as well. In which case, just simply do the following in your KeywordAdCategory class to do the proper mapping:
[Key, ForeignKey("Keyword")]
[Column("Keyword_Id", Order = 0)]
public int Keyword_Id { get; set; }
[Key, ForeignKey("Ad")]
[Column("Ad_Id", Order = 1)]
public int Ad_Id { get; set; }
[Key, ForeignKey("Category")]
[Column("Category_Id", Order = 2)]
public int Category_Id { get; set; }
public virtual Keyword Keyword { get; set; }
public virtual Ad Ad { get; set; }
public virtual Category Category { get; set; }
Doing this should do the proper mappings, put FKs on your KeywordAdCategory table, and thus give you the ability to have good navigation properties to the other objects.
Related
I have a case scenario with two tables References and Products alreading containing many entries which can be dynamically related on demand.
public class Reference
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ReferenceId { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public virtual ICollection<Product> ManyProducts { get; set; }
public Reference() {}
}
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
[ForeignKey("Reference")]
public Guid ReferenceId { get; set; }
public virtual Reference OneReference { get; set; }
public Product() {}
}
When a user ask to link a reference to a product I simply do :
product.ReferenceId = reference.ReferenceId ;
await context.SaveChangesAsync() ;
The entry in Products table is updated correctly, but when I try to access a reference's related data, it does not retrieve any ?? After eager loading :
var reference = await context.References
.Include(r => r.ManyProducts)
.SingleAsync(r => r.ReferenceId == referenceId) ;
or explicit loading :
var reference = await context.References.FindAsync(referenceId) ;
await context.Entry(reference).Collection(s => s.ManyProducts).LoadAsync() ;
reference.ManyProducts is empty. So I have to do something like this :
var reference = await context.References.FindAsync(referenceId) ;
var products = await context.Products.Where(l => l.ReferenceId == referenceId).ToListAsync() ;
result.ManyProducts = products ;
which works fine, but I would like to understand why ?
I´m using DataAnnotation
Sample
public class spread
{
[Key]
public int spreadid { get; set; }
[Required]
public DateTime insertdate { get; set; }
[Required]
public int exchangeid { get; set; }
[ForeignKey("exchangeid"), Display(Name = "Exchange origem")]
public virtual exchange exchange { get; set; } // One to one
[ForeignKey("spreadid")]
public virtual ICollection<spreadhelper> spreadhelper { get; set; } // One to many
}
public class spreadhelper
{
[Key]
public int spreadhelperid { get; set; }
[Required]
public int spreadid { get; set; }
[Required]
public int exchangeid { get; set; }
[ForeignKey("exchangeid"), Display(Name = "Exchange")] // One to one
public virtual exchange exchange { get; set; }
[Required, Range(0, 200)]
public decimal spreadvalue { get; set; }
}
one to one - sample
public class exchange
{
[Key]
public int exchangeid { get; set; }
[Required]
public DateTime insertdate { get; set; }
[Required, MaxLength(50)]
public string name { get; set; }
[MaxLength(128)]
public string token { get; set; }
}
One to many sample
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.
My data class is
public class Data
{
public int Id { get; set; }
public int LeagueId { get; set; }
public League League { get; set; }
public int HomeTeamId { get; set; }
public virtual Team HomeTeam { get; set; }
public int AwayTeamId { get; set; }
public virtual Team AwayTeam { get; set; }
}
and my team class is
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Data> Datas { get; set; }
}
which generates an extra foreign key FK_dbo.Data_dbo.Teams_Team_Id and also and extra column in my Data table.
So my first question is, how that foreign-key was created there?
Can i have two one to many relationships that target at the same table with entity framework?
I need to set both the HomeTeamId and the AwayTeamId in the Data table as one to many relationship
Try:
public class Data
{
public int Id { get; set; }
public int LeagueId { get; set; }
[ForeignKey("LeagueId")] /* Add explicit foreign key data annotations */
public League League { get; set; }
public int HomeTeamId { get; set; }
[ForeignKey("HomeTeamId")]
public virtual Team HomeTeam { get; set; }
public int AwayTeamId { get; set; }
[ForeignKey("AwayTeamId")]
public virtual Team AwayTeam { get; set; }
}
public class Team
{
public Team()
{
this.HomeTeamData = new HashSet<Data>();
this.AwayTeamData = new HashSet<Data>();
}
public int Id { get; set; }
public string Name { get; set; }
[InverseProperty("HomeTeam")]
public virtual ICollection<Data> HomeTeamData { get; set; }
[InverseProperty("AwayTeam")]
public virtual ICollection<Data> AwayTeamData { get; set; }
}
Let me know if this helps.
I suspect you may be hitting the limit of Entity's ability to figure out what you want. You may need to consider using some Entity Annotations to instruct Entity on what you want it to actually do.
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?
I have a setup like this:
[Table("tablename...")]
public class Branch
{
public Branch()
{
Users = new List<User>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public List<User> Users { get; set; }
}
[Table("tablename...")]
public class User
{
[Key]
public int Id {get; set; }
public string Username { get; set; }
public string Password { get; set; }
[ForeignKey("ParentBranch")]
public int? ParentBranchId { get; set; } // Is this possible?
public Branch ParentBranch { get; set; } // ???
}
Is it possible for the User to know what parent branch it belongs to? The code above does not populate the ParentBranch.
Entity Framework version 5.0
.NET 4.0
c#
Try making navigation properties virtual,
[Table("tablename...")]
public class Branch
{
public Branch()
{
Users = new List<User>();
}
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual List<User> Users { get; set; }
}
[Table("tablename...")]
public class User
{
[Key]
public int Id {get; set; }
public string Username { get; set; }
public string Password { get; set; }
[ForeignKey("ParentBranch")]
public int? ParentBranchId { get; set; } // Is this possible?
public virtual Branch ParentBranch { get; set; } // ???
}