I recently inherited an ASP.NET Entity Framework API project.
I managed to do basic changes that were needed, but I'm getting a little lost with advanced SQL requests (I'm more a Symfony dev, I don't know Entity Framework).
I need to add a GET method to my API that will take a service (prestation) and will return a list of all the partners (Partenaires) who has a service (Prestation) with the same name as the GET parameter.
Here's the actual prototype of the method:
// GET: api/Partenaires_prestations
[Authorize]
public List<PartenaireMapItem> GetPartenairesWithPrestations(string prestation = "")
{
if (string.IsNullOrWhiteSpace(prestation))
{
prestation = "";
}
return db.Partenaires
.Join() // Here I don't know what to do
}
I have 3 tables that I have to use:
Prestation, Partenaires, PartenairesPrestation
Here are the 3 tables classes:
namespace Uphair.EfModel
{
using System;
using System.Collections.Generic;
public partial class Partenaire
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Partenaire()
{
this.PartenairePrestations = new HashSet<PartenairePrestation>(); // I took out the useless parts
}
public int IdPartenaire { get; set; }
[...] // I took out properties that are not needed
public virtual ICollection<PartenairePrestation> PartenairePrestations { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
}
namespace Uphair.EfModel
{
using System;
using System.Collections.Generic;
public partial class PartenairePrestation
{
public int IdPartenaire { get; set; }
public int IdPrestation { get; set; }
public double Prix { get; set; }
public int Duree { get; set; }
public Nullable<System.DateTime> DateAjout { get; set; }
public virtual Partenaire Partenaire { get; set; }
public virtual Prestation Prestation { get; set; }
}
}
namespace Uphair.EfModel
{
using System;
using System.Collections.Generic;
public partial class Prestation
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Prestation()
{
this.PartenairePrestations = new HashSet<PartenairePrestation>();
this.PrixDureeOptions = new HashSet<PrixDureeOption>();
this.LigneReservations = new HashSet<LigneReservation>();
}
public int IdPrestation { get; set; }
public string NomPrestation { get; set; }
public int Categorie { get; set; }
public Nullable<int> CoifEsthe { get; set; }
public Nullable<int> IdPrestationCategorie { get; set; }
public virtual ICollection<PartenairePrestation> PartenairePrestations { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
}
The last one makes the link between Partenaires and Prestation via IdPartenaire and IdPrestation columns.
Here's a screenshot of my model structure:
https://imageshack.com/a/img922/9111/4twiC8.png (imgur is not responding sorry)
Here's the PartenaireMapItem model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Uphair.EfModel;
namespace Uphair.Api.Models.Partenaire
{
public class PartenaireMapItem
{
public int IdPartenaire { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string NomComplet { get; set; }
public double? Lat { get; set; }
public double? Lng { get; set; }
public PartenaireType Type { get; set; }
public int DureeMin { get; set; }
public string ImageUrl { get; set; }
public int SeDeplace { get; set; }
public bool ADomicile { get; set; }
public double NoteGlobale { get; set; }
public List<String> Prestations { get; set; }
}
}
I need to use join to get a list of partners (Partenaires) that have the service (Prestation) with the service name provided in the GET parameter, but I don't know how to do it.
Any help would be welcome, thanks to anyone who will take the time to read/answer me.
Related
I'm trying to do the migration from my properties on Models, and is returning this message:
The property 'DadosRequisicao.CnpjFornecedor' could not be mapped because it is of type 'List<string>', which is not a supported primitive type or a valid entity type. Either explicitly map this property, or ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
My code:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace PortalDeCotacao.Models
{
public class DadosRequisicao
{
[Key]
[Required]
public int Id { get; set; }
public string DataLimiteCot { get; set; }
public string ObservacoesReq { get; set; }
public List<string> CnpjFornecedor { get; set; } = new List<string>();
public List<int> CodProduto { get; set; } = new List<int>();
}
}
I didn't understand where is the problem. what should I change to migrate the properties?
You are trying to generate a One-To-Many relationship in the wrong way. You can try the following approach:
public class DadosRequisicao
{
[Key]
[Required]
public int Id { get; set; }
public string DataLimiteCot { get; set; }
public string ObservacoesReq { get; set; }
public List<CnpjFornecedor> CnpjFornecedor { get; set; } = new();
public List<CodProduto> CodProduto { get; set; } = new();
}
public class CnpjFornecedor
{
public int Id { get; set; }
public DadosRequisicao DadosRequisicao { get; set; }
public string Data { get; set; }
}
public class CodProduto
{
public int Id { get; set; }
public DadosRequisicao DadosRequisicao { get; set; }
public int Data { get; set; }
}
Now you have a correct One-To-Many relationship with navigation property.
Migration is successful, yet when trying to update the database, I get that error.
I had a similar issue before, because I did not create a proper DbSet<> for the table. This time, it's not the case.
My DBContext:
using System;
using System.Collections.Generic;
using System.Text;
using ArtGalleries.Domain;
using Microsoft.EntityFrameworkCore;
namespace ArtGalleries.Data
{
public class ArtGalleriesContext:DbContext
{
public ArtGalleriesContext(DbContextOptions<ArtGalleriesContext> options):base(options)
{
}
public DbSet<ArtItem> ArtItems { get; set; }
public DbSet<Artist> Artists { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<Floor> Floors { get; set; }
public DbSet<Location> Locations { get; set; }
public DbSet<Room> Rooms { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserLocation>()
.HasKey(u => new {u.UserId, u.LocationId});
//modelBuilder.Entity().
//modelBuilder.Entity<Company>()
// .HasOne(c => c.Company)
// .WithOne(pc => pc.Company)
// .HasForeignKey(fk => fk.ParentId);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(
"Server=(localdb)\\mssqllocaldb;Database=GalleriesDB;Trusted_Connection=True;");
}
}
}
}
My problem class:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace ArtGalleries.Domain
{
public class ArtItem
{
public string ArtType { get; set; }
public Artist Artist { get; set; }
public int ArtistId { get; set; }
public int Depth { get; set; }
public string Description { get; set; }
public string Framing { get; set; }
public int Height { get; set; }
[Required]
public int Id { get; set; }
public Location Location { get; set; }
[Required]
public int LocationId { get; set; }
public string Materials { get; set; }
[Required]
public string Name { get; set; }
public User Owner { get; set; }
public int OwnerId { get; set; }
public string Picture { get; set; }
public Room Room { get; set; }
public int RoomId { get; set; }
public string Technique { get; set; }
public int Width { get; set; }
public int YearOfAcquisition { get; set; }
public int YearOfCreation { get; set; }
public Status Status { get; set; }
}
}
I am unfamiliar with permissions. I noticed a similar issue where the person was suggested to find Up() and Down() methods and work with them. I do not have such a file. It might be because their issue was generated by EF and not EF Core.
Similar problem title: “Cannot find the object ”dbo.xxxx“ because it does not exist or you do not have permissions.”
This was solved by removing the migration and adding a new migration, no edits to the code made. Weird.
I'm trying to create a 1:1 relationship between two Entity Framework code-first models between Customer and MembershipType. Their models are:
Customer.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Vidly.Models
{
public class Customer
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
public bool IsSubscribedToNewsletter { get; set; }
public MembershipType MembershipType { get; set; }
[Display(Name = "Membership Type")]
public byte MembershipTypeId { get; set; }
[Display(Name = "Date of Birth")]
public DateTime? Birthdate { get; set; }
}
}
MembershipType.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Vidly.Models
{
public class MembershipType
{
public int Id { get; set; }
public string Name { get; set; }
public short SignupFee { get; set; }
public byte DurationInMonths { get; set; }
public byte DiscountRate { get; set; }
}
}
And when the migration is ran it results in the following Customer table:
Why does this happen? It's causing issues when trying to use an Html helper to create a drop down box, as when it saves it wants to put the data into the MembershipTypeId column but it appears entity is actually using the MembershipType_Id column.
you can try with the following code:
namespace Vidly.Models
{
public class Customer
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
public bool IsSubscribedToNewsletter { get; set; }
[Display(Name = "Membership Type")]
public byte MembershipTypeId { get; set; }
[Display(Name = "Date of Birth")]
public DateTime? Birthdate { get; set; }
public virtual MembershipType MemshipType { get; set; }
}
public class MembershipType
{
public int Id { get; set; }
public string Name { get; set; }
public short SignupFee { get; set; }
public byte DurationInMonths { get; set; }
public byte DiscountRate { get; set; }
public virtual Customer customer{ get; set; }
}
}
For More info and other ways of doing the same, kindly refer this useful link:http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx
Hope it will be helpful
Thanks
Karthik
I am working on a project for school, and got a bit stuck on this.
A booking has 3 navigation properties, 1 customer and 2 airports.
To get the CustomerCode in one of the views for a booking, I can use (db.Bookings.Include(b => b.Customer)).
When I try to do the same for Origin and/or Destination (db.Bookings.Include(b => b.Origin)), nothing happens.
I can work around it by finding and setting both origin and destination by using a second query. (booking.Origin = db.Airports.Find(id))
But I would like to know why the Include isn't working, and if there is a more elegant way of loading the airports on a booking.
Booking class
public int BookingID { get; set; }
public int CustomerID { get; set; }
public int OriginID { get; set; }
public int DestinationID { get; set; }
public string Awb { get; set; }
public string ClientRef { get; set; }
public string Info { get; set; }
// Navigation
public virtual Airport Origin { get; set; }
public virtual Airport Destination { get; set; }
public virtual Customer Customer { get; set; }
Customer class
public int CustomerID { get; set; }
public string CustomerCode { get; set; }
public string CompanyName { get; set; }
public string VatNumber { get; set; }
Airport class
public int AirportID { get; set; }
public string AirportCode { get; set; }
Controller
public ActionResult Index()
{
var bookings = db.Bookings.Include(b => b.Origin).Include(b => b.Destination).Include(b => b.Customer);
return View(bookings.ToList());
}
Context
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
public class AppContext : DbContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to drop and regenerate your database
// automatically whenever you change your model schema, please use data migrations.
// For more information refer to the documentation:
// http://msdn.microsoft.com/en-us/data/jj591621.aspx
public AppContext() : base("name=AppContext")
{
}
public System.Data.Entity.DbSet<Tester.Models.Country> Countries { get; set; }
public System.Data.Entity.DbSet<Tester.Models.Airport> Airports { get; set; }
public System.Data.Entity.DbSet<Tester.Models.Customer> Customers { get; set; }
public System.Data.Entity.DbSet<Tester.Models.Booking> Bookings { get; set; }
}
As suggested by Alexander Derck, use [ForeignKey] attribute.
Booking class
public int BookingID { get; set; }
public int CustomerID { get; set; }
[ForeignKey("Origin")]
public int OriginID { get; set; }
[ForeignKey("Destination")]
public int DestinationID { get; set; }
public string Awb { get; set; }
public string ClientRef { get; set; }
public string Info { get; set; }
// Navigation
public virtual Airport Origin { get; set; }
public virtual Airport Destination { get; set; }
public virtual Customer Customer { get; set; }
Origin is a Property. Is not possible use for include. Maybe you not like try like this:
Booking.Include(a=> a.Airport)
When attempting to create an Entity Framework database model using attributes as lined out in MS Data Developer Center, I'm unable to add the ForeignKey attribute. Do I need to add another using statement to my code?
Here's a copy of the code:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Tester.Models
{
public class MyClass
{
[Key]
public int ID { get; set; }
public string name { get; set; }
public virtual List<Note> Notes { get; set; }
public virtual List<Segment> Segments { get; set; }
}
public class Segment
{
public int ID { get; set; }
public string name { get; set; }
public virtual List<Note> segNotes { get; set; }
}
public class Note
{
public int ID { get; set; }
public DateTime notetimestamp { get; set; }
public string notestring { get; set; }
}
}
using System.ComponentModel.DataAnnotations.Schema;
Supported in .NET framework 4.5 and higher