EF Core can't include children in parent - entity-framework

I'm quite new to EF Core.
In my DB Context:
// STEP
modelBuilder.Entity<CorsoStepS>().HasKey(x => new { x.codCorso, x.codStep });
modelBuilder.Entity<CorsoStepS>()
.HasMany(step => step.CorsoStepLezioni)
.WithOne(lez => lez.CorsoStep)
.HasForeignKey(lez => new { lez.codCorso, lez.codStep });
modelBuilder.Entity<CorsoStepS>().Ignore(step => step.CorsoStepLezioni);
////
// LEZIONI
modelBuilder.Entity<CorsoStepLezione>().HasKey(x => new { x.codCorso, x.codStep, x.codLezione });
modelBuilder.Entity<CorsoStepLezione>()
.HasMany(lez => lez.Sessioni)
.WithOne(sess => sess.Lezione)
.HasForeignKey(sess => new { sess.codCorso, sess.codStep, sess.codLezione });
modelBuilder.Entity<CorsoStepLezione>().Ignore(lez => lez.Sessioni);
////
// SESSIONI
modelBuilder.Entity<CorsoStepLezioneSessione>().HasKey(x => new { x.codCorso, x.codStep, x.codLezione, x.codSessione });
modelBuilder.Entity<CorsoStepLezioneSessione>()
.HasMany(sess => sess.Iscrizioni)
.WithOne(iscr => iscr.Sessione)
.HasForeignKey(iscr => new { iscr.CodCorso, iscr.CodStep, iscr.CodLezione, iscr.CodSessione });
modelBuilder.Entity<CorsoStepLezioneSessione>().Ignore(sess => sess.Iscrizioni);
////
My entities:
public class CorsoStepS
{
public int codCorso { get; set; }
public int codStep { get; set; }
public string nome { get; set; }
public int maxPartecipanti { get; set; }
public int order { get; set; }
public virtual Corso Corso { get; set; }
public virtual ICollection<CorsoStepLezione> CorsoStepLezioni { get; set; }
}
public class CorsoStepLezione
{
public int codCorso { get; set; }
public int codStep { get; set; }
public int codLezione { get; set; }
public string nome { get; set; }
public CorsoStepS CorsoStep { get; set; }
public virtual ICollection<CorsoStepLezioneSessione> Sessioni { get; set; }
}
public class CorsoStepLezioneSessione
{
public int codCorso { get; set; }
public int codStep { get; set; }
public int codLezione { get; set; }
public int codSessione { get; set; }
public DateTime? data { get; set; }
public string ora { get; set; }
public int maxPartecipanti { get; set; }
public virtual CorsoStepLezione Lezione { get; set; }
public virtual ICollection<CorsoStepLezioniSessioniIscrizione> Iscrizioni { get; set; }
}
When I call:
var lezioniCorso = _clienteContext.CorsoStepLezioni
.Include(lezione => lezione.Sessioni);
it gives me:
The expression 'lezione.Sessioni' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'.
But if I call:
var lezioniCorso = _clienteContext.CorsoStepLezioni
.Include(lezione => lezione.CorsoStep);
it's ok.
what am I doing wrong? I'm going stupid

It is because of this line
modelBuilder.Entity<CorsoStepLezione>().Ignore(lez => lez.Sessioni);
First you are telling EF to build up the relationship and then immediately ignore it again so EF acts as if this property does not exist.

Related

Entity-framework The column name is specified more than once in the SET clause or column list of an INSERT

I have entity
public class ImageTeam
{
public int Id { get; set; }
public int TeamID { get; set; }
public Team Team { get; set; }
public int PostTeamID { get; set; }
public string Image { get; set; }
public int ImageType { get; set; }
public int StatusPublic { get; set; }
public int StatusActive { get; set; }
public DateTime CreatedAt { get; set; }
}
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public int NoMember { get; set; }
public float Score { get; set; }
public int StatusActive { get; set; }
public int TeamType { get; set; }
public virtual List<TeamGroup> ListMember { get; set; }
public virtual List<ImageTeam> ListAvatar { get; set; }
public virtual List<ImageTeam> ListBanner { get; set; }
public DateTime CreatedAt { get; set; }
}
config data context
modelBuilder.Entity<Team>(entity =>
{
entity.HasMany(x => x.ListAvatar)
.WithOne(t => t.Team)
.HasForeignKey(pv => pv.TeamID);
});
when I post the data insert a new record entity ImageTeam then it show exception
I need to do...Help me
In the Team class you add another relation ListBanner to ImageTeam class ,you have not set an foreign key for it, so EF automatically creates a TeamID and because TeamId already in the class, it's throw exception . You also need to set an foreign key for second relation.
public class ImageTeam
{
public int Id { get; set; }
public int TeamID { get; set; }
public Team Team { get; set; }
public int BannerTeamId { get; set; }
public Team BannerTeam { get; set; }
public int PostTeamID { get; set; }
public string Image { get; set; }
public int ImageType { get; set; }
public int StatusPublic { get; set; }
public int StatusActive { get; set; }
public DateTime CreatedAt { get; set; }
}
entity.HasMany(x => x.ListAvatar)
.WithOne(t => t.Team)
.HasForeignKey(pv => pv.TeamID).OnDelete(DeleteBehavior.Restrict);
entity.HasMany(x => x.ListBanner)
.WithOne(t => t.BannerTeam)
.HasForeignKey(pv => pv.BannerTeamId).OnDelete(DeleteBehavior.Restrict);
I have found a solution:
edit Team entity:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public int NoMember { get; set; }
public float Score { get; set; }
public int StatusActive { get; set; }
public int TeamType { get; set; }
public virtual List<TeamGroup> ListMember { get; set; }
public virtual List<ImageTeam> ListImage { get; set; }
public DateTime CreatedAt { get; set; }
}
*no config data context
create new model: TeamViewModel
public class TeamViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public int NoMember { get; set; }
public float Score { get; set; }
public int StatusActive { get; set; }
public int TeamType { get; set; }
public virtual List<TeamGroupViewModel> ListMember { get; set; }
public virtual List<ImageTeam> ListImage { get; set; }
public string AvatarUrl { get; set; }
public virtual List<ImageTeam> ListAvatar { get; set; }
public string BannerUrl { get; set; }
public virtual List<ImageTeam> ListBanner { get; set; }
public virtual List<ImageTeam> ListPost { get; set; }
}
in controller :
[Route("api/[controller]/{id}/view")]
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var team = _teamService.GetById(id);
var model = _mapper.Map<TeamViewModel>(team);
model = parserImageTeam(model);
return Ok(model);
}
[Route("api/[controller]/{UserId}/view-teams")]
[HttpGet("{UserId}")]
public IActionResult GetAllTeamOfUser(int UserId)
{
// list teams
var teams = _teamService.GetTeamOfUser(UserId);
var _teams = _mapper.Map<IList<TeamViewModel>>(teams);
var newTeams = new List<TeamViewModel>();
foreach (TeamViewModel team in _teams)
{
newTeams.Add(parserImageTeam(team));
}
return Ok(newTeams);
}
private TeamViewModel parserImageTeam(TeamViewModel teamModel)
{
var imageAvatars = new List<ImageTeam>();
var imageBanners = new List<ImageTeam>();
var imagePosts = new List<ImageTeam>();
bool avt = false, banner = false;
foreach (ImageTeam image in teamModel.ListImage)
{
if (image.ImageType == Constants.ImageType.IMAGE_AVATAR_TEAM)
{
image.Image = parserUrlImage(image);
imageAvatars.Add(image);
if (!avt)
{
teamModel.AvatarUrl = image.Image;
avt = true;
}
}
if (image.ImageType == Constants.ImageType.IMAGE_BANNER_TEAM)
{
image.Image = parserUrlImage(image);
imageBanners.Add(image);
if (!banner)
{
teamModel.BannerUrl = image.Image;
banner = true;
}
}
if (image.ImageType == Constants.ImageType.IMAGE_POST_TEAM)
{
image.Image = parserUrlImage(image);
imagePosts.Add(image);
banner = true;
}
}
teamModel.ListAvatar = imageAvatars;
teamModel.ListBanner = imageBanners;
teamModel.ListPost = imagePosts;
return teamModel;
}
private string parserUrlImage(ImageTeam model)
{
string url = Configuration.GetValue<string>("BaseVariables:BaseUrl");
// another controller handle request (ImagesController)
return model.Image = url + "/Images/" + Constants.ImageType.getFolderName(model.ImageType).ToLower() + "/" + model.TeamID + "?ImageType=" + model.ImageType + "&imageName=" + model.Image;
}

Defining the one to many relationship in OnModelCreating using Entity Framework Core 3.1

I am new to Entity Framework Core 3.1 and trying to define the one-to-many relationship between two tables. I am currently struggling and getting compilation errors. Could somebody tell me what the problem could be.
The error is:
PersonNote does not contain the definition for PersonNote
I am currently getting is at line
entity.HasOne(d => d.PersonNote)
How else could I define one-to-many relationship?
The two tables are Person and PersonNote. One Person can have many PersonNotes. I have defined the models for them
public class Person
{
public int Id { get; set; }
public int? TitleId { get; set; }
public string FirstName { get; set; }
public string FirstNamePref { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime? DateOfBirth { get; set; }
public string Gender { get; set; }
public int AddressId { get; set; }
public string TelephoneNumber { get; set; }
public string MobileNumber { get; set; }
public string Email { get; set; }
public int? PartnerId { get; set; }
public bool Enabled { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
public string ModifiedBy { get; set; }
public DateTime Modified { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
public Address Address { get; set; }
public Title Title { get; set; }
public Client Client { get; set; }
internal static IEnumerable<object> Include(Func<object, object> p)
{
throw new NotImplementedException();
}
public PersonNote PersonNote { get; set; }
}
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
}
public IEnumerable<PersonNote> GetPersonNotes(int personId)
{
var PersonNotes = PersonNote
.Include(x => x.)
.Where(x => x.Id == personId)
.ToList();
return PersonNotes;
}
I have tried the following in OnModelCreating:
modelBuilder.Entity<PersonNote>(entity =>
{
entity.ToTable("PersonNote", "common");
entity.HasOne(d => d.PersonNote)
.WithMany(p => p.Person)
.HasForeignKey(d => d.PersonId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_commonPersonNote_commonPerson");
});
You should have have something like this (other properties are omitted):
class Person
{
[Key]
public int Id { get; set; }
public List<PersonNote> PersonNotes { get; set; }
}
class PersonNote
{
[Key]
public int Id { get; set; }
public int PersonId { get; set; }
}
class StackOverflow : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<PersonNote> PersonNotes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasMany(p => p.PersonNotes)
.WithOne()
.HasForeignKey(p => p.PersonId);
}
}

EF Lambda How to make projection for GroupJoin

I am trying to query EF models. (GameBank and GameCouponBank) How can I make a projection for left outer join (GoupJoin)?
Can I make projection for Coupons?
Here is my query
var gameBankResult = context.GameBanks.GroupJoin(context.GameCouponBanks, g => g.GameBankID, gc => gc.GameBankID,
(g,gc) => new {
g.quantity,
g.currency,
g.initiationResultCode,
g.productCode,
g.productDescription,
g.referenceId,
g.responseDateTime,
g.unitPrice,
g.totalPrice,
Coupons = gc
})
.Where(g => g.productCode == initiate.productCode)
.Select(s => s);
Here is models:
public class GameBank
{
public int GameBankID { get; set; }
public string referenceId { get; set; }
public string productCode { get; set; }
public int quantity { get; set; }
public string version { get; set; }
public DateTime? requestDateTime { get; set; } = DateTime.Now;
public int? customerID { get; set; }
public string password { get; set; }
public DateTime? responseDateTime { get; set; } = DateTime.Now;
public string initiationResultCode { get; set; }
public string companyToken { get; set; }
public int used { get; set; }
public string productDescription { get; set; }
public string currency { get; set; }
public double unitPrice { get; set; }
public double totalPrice { get; set; }
public virtual List<GameCouponBank> coupons { get; set; }
}
public class GameCouponBank
{
public int Id { get; set; }
public int GameBankID { get; set; }
public DateTime? expiryDate { get; set; }
public string Serial { get; set; }
public string Pin { get; set; }
}
You don't need to use GroupJoin explicitly. You can simply project your query as follows:
var gameBankResult = context.GameBanks.Where(g => g.productCode == initiate.productCode)
.Select(g => new {
g.quantity,
g.currency,
g.initiationResultCode,
g.productCode,
g.productDescription,
g.referenceId,
g.responseDateTime,
g.unitPrice,
g.totalPrice,
Coupons = g.coupons.Select(c => new {c.Id, c.GameBankID,...}).ToList() //<-- Here is the projection for coupons
}).FirstOrDefault(); // I assume you are returning single entity, if not then use `.ToList()` instead of `.FirstOrDefault()`

Json response does not contain all the navigation properties EntityFramework Core and ASP .NETCore Web API

I have migrated from Entity Framework 6 to EF Core and also Web Api .net framework to .net core.
I have many to many relationship that I have set up as follows
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var instrumentsToPlaces = modelBuilder.Entity<InstrumentPlace>();
instrumentsToPlaces.ToTable("InstrumentsToPlaces");
instrumentsToPlaces.HasKey(x => new { x.PlaceId, x.InstrumentId });
instrumentsToPlaces.HasOne(i => i.Instrument)
.WithMany(p => p.InstrumentsPlaces)
.HasForeignKey(ip => ip.InstrumentId);
instrumentsToPlaces.HasOne(p => p.Place)
.WithMany(i => i.InstrumentsPlaces)
.HasForeignKey(ip => ip.PlaceId);
var instrumentsToStyle = modelBuilder.Entity<InstrumentStyle>();
instrumentsToStyle.ToTable("InstrumentsToStyles");
instrumentsToStyle.HasKey(x => new { x.StyleId, x.InstrumentId });
instrumentsToStyle.HasOne(i => i.Instrument)
.WithMany(s => s.InstrumentStyles)
.HasForeignKey(si => si.InstrumentId);
instrumentsToStyle.HasOne(s => s.Style)
.WithMany(i => i.InstrumentStyles)
.HasForeignKey(si => si.StyleId);
}
I have included the navigation properties in the repository method as follows
public Instrument GetInstrumentByName(string name)
{
using (var starsAndCatzDbContext = new StarsAndCatzDbContext())
{
var instrument = _starsAndCatzDbContext.Instruments
.Include(a=>a.InstrumentsPlaces)
.ThenInclude(a=>a.Place)
.Include(a=>a.InstrumentStyles)
.ThenInclude(a=>a.Style)
.FirstOrDefault(i => i.Name == name);
return instrument;
}
}
Here are the classes
public class Instrument {
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<InstrumentPlace> InstrumentsPlaces { get; set; }
public virtual ICollection<InstrumentStyle> InstrumentStyles { get; set; }
}
public class InstrumentPlace
{
public int InstrumentId { get; set; }
public Instrument Instrument { get; set; }
public int PlaceId { get; set; }
public Place Place { get; set; }
}
public class InstrumentStyle
{
public int InstrumentId { get; set; }
public Instrument Instrument { get; set; }
public int StyleId { get; set; }
public Style Style { get; set; }
}
public class Style {
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<InstrumentStyle> InstrumentStyles { get; set; }
}
public class Place {
public int Id { get; set; }
public string Name { get; set; }
public string Division { get; set; }
public int Tier { get; set; }
public string State { get; set; }
public string Postcode { get; set; }
public float? Latitude { get; set; }
public float? Longitude { get; set; }
public virtual ICollection<InstrumentPlace> InstrumentsPlaces { get; set; }
}
The WebAPI method to be called is
[HttpGet("GetInstrumentByName/{suburb}/{instrument}"), Produces("application/json")]
public Instrument GetInstrumentByName(string suburb, string instrument)
{
try
{
var result = _instrumentRepository.GetInstrumentByName(instrument);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return new Instrument();
}
}
When I send the request to "/api/instruments/west-end/guitar" I get the expected result when I place a breakpoint before sending the response as follows
As you notice, the Navigation properties are loaded (when I expand the collections I can see all the properties being loaded as well).
However the json response I receive is the following
Any suggestions or am I missing something here?
Thank you all in advanced
Thanks #H. Herzl for giving me a hint.
The solution was found in this other question
services.AddMvc().AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
https://stackoverflow.com/a/40501464/1513346

EF Adding an additional FK?

I have the following 2 entities:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Fixture> Fixtures { get; set; }
}
public class Fixture
{
public int Id { get; set; }
public Result Result { get; set; }
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team AwayTeam { get; set; }
}
I have then mapped it like so:
public class FixtureMap : EntityTypeConfiguration<Fixture>
{
public FixtureMap()
{
HasRequired(x => x.AwayTeam).WithMany().HasForeignKey(x => x.AwayTeamId);
HasRequired(x => x.HomeTeam).WithMany().HasForeignKey(x => x.HomeTeamId);
}
}
But when I add a migration, EF is creating an additional FK and column to my Fixture table and I've no idea why? How can I tell it not too?
As you can see its added a column called Team_Id and created an FK from it even tho I have specified the relationship in the mapping?
use this code:
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
[InverseProperty("HomeTeam")]
public virtual ICollection<Fixture> HomeFixtures { get; set; }
[InverseProperty("AwayTeam")]
public virtual ICollection<Fixture> AwayFixtures { get; set; }
}
public class Fixture
{
public int Id { get; set; }
public Result Result { get; set; }
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
[InverseProperty("HomeFixtures")]
[ForeignKey("HomeTeamId ")]
public virtual Team HomeTeam { get; set; }
[InverseProperty("AwayFixtures")]
[ForeignKey("AwayTeamId")]
public virtual Team AwayTeam { get; set; }
}
And :
public class FixtureMap : EntityTypeConfiguration<Fixture>
{
public FixtureMap()
{
HasRequired(x => x.AwayTeam).WithMany().HasForeignKey(x => x.AwayTeamId).willCascadeOnDelete(false);
HasRequired(x => x.HomeTeam).WithMany().HasForeignKey(x => x.HomeTeamId);
}
}