C# Join Clause with association table - c#

I have 3 classes : (Personnel, Chirurgien and Operation)
public class Personnel
{
[Key]
public int CodePersonel { get; set; }
public FullName NomComplet { get; set; }
public Adresse Adress { get; set; }
public int Age { get; set; }
public ICollection<Operation> Operation { get; set; }
}
Chirurgien
public class Chirurgien : Personnel
{
public int Nbre_anne_Exp { get; set; }
public int NoteXP { get; set; }
}
and Operation:
public class Operation
{
public int OperationId { get; set; }
public DateTime DateDebut { get; set; }
public DateTime DateFin { get; set; }
public int Duree { get; set; }
public bool Etat { get; set; }
public string CIN { get; set; }
public ICollection<Personnel> Personel { get; set; }
public Patient Patients { get; set; }
public override string ToString()
{
return CIN;
}
}
And I have also created an association table "Membre"
HasMany(p => p.Personel).WithMany(v => v.Operation).Map(m => {
m.ToTable("Membre");
m.MapLeftKey("Operation");
m.MapRightKey("Personel");
});
How can I get Chirurgien list that have failed Operation (Operation Etat=false) ??
I used this code to return the full Chirurgien list:
public ICollection<Chirurgien> NoobDoctors()
{
var req = from t in ut.getRepository<Chirurgien>().GetAll()
select t;
return req.ToList();
}
Thank you

How can I get Chirurgien list that have failed Operation (Operation Etat=false) ??
You can use Operation navigation property with Any for filtering:
var result = from c in ut.getRepository<Chirurgien>().GetAll()
where c.Operation.Any(o => !o.Etat)
select c;
Since you have configured many-to-many relationship with an implicit junction table, EF will maintain the table (including query joins) for you.

Related

EF6 - Many-to-One Relationship not working

I have Products, Sub products, and more tables. You can see in the code, relationship not working I want it Product Class relationship with SubProduct but always the collection count is 0.
Product Class:
[Key]
public int Id { get; set; }
public bool Status { get; set; } = true;
public string StockCode { get; set; }
public int StockDecrease { get; set; }
public string Name { get; set; }
public int Amount { get; set; }
public int Desi { get; set; }
public string Barcode { get; set; }
public long Gtin { get; set; }
public string InvoiceName { get; set; }
public string EInvoiceName { get; set; }
public string Subtitle { get; set; }
public byte Kdv { get; set; }
public virtual Category Category { get; set; }
public string Description { get; set; }
public virtual ICollection<SubProduct> SubProducts { get; set; }
public virtual ICollection<ProductVariant> ProductVariants { get; set; }
Sub Product Class:
public int Id { get; set; }
public int ProductId { get; set; }
public virtual Product Product { get; set; }
public string StockCode { get; set; }
public virtual ProductBrand Brand { get; set; }
public virtual Company Company { get; set; }
public Abstract.Marketplace Marketplace { get; set; }
public string Barcode { get; set; }
public string Title { get; set; }
public string SubTitle { get; set; }
public bool IsConnected { get; set; }
public decimal Price { get; set; }
public decimal PriceDiscount { get; set; }
public string Description { get; set; }
public virtual ICollection<SubProductVariant> SubProductVariants { get; set; }
Repository Base:
public async System.Threading.Tasks.Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> filter)
{
await using var context = new TContext();
return await context.Set<TEntity>().Where(filter).SingleOrDefaultAsync();
}
Make sure to add using System.Data.Entity; to get the version of Include that takes in a lambda.
using System.Data.Entity;
query.Include(x => x.SubProducts)
and for more use ThenInclude or Include extention methods.
To define a method on the repository for this, you can use this example:
public static IQueryable<TSource> GetIQueryableWithIncludes<TSource>(Expression<Func<TSource, object>>[] includeProperties, IQueryable<TSource> result)
{
var newResult = result;
if (includeProperties.Any())
{
foreach (var includeProperty in includeProperties)
{
newResult = newResult.Include(includeProperty);
}
}
return newResult;
}
You can now pass a list of lamba expression like p => p.SubProjects to specify what you want to include.
You can further hide this by making an GetAll method that hides these includes from the outside user of your Domain
I would suggest to first study more about how to handle related entities.
You basically need to tell EF to load them in.
See documentation
Simplest example would something like this:
// Load all products.
var products= context.Products
.Include(b => b.SubProducts)
.ToList();
I solved with .Include() thanks for helping.
public async System.Threading.Tasks.Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> filter, Expression<Func<TEntity,object>> include=null)
{
await using var context = new TContext();
return await context.Set<TEntity>().Where(filter).Include(include).SingleOrDefaultAsync(filter);
}

How to get data from child to parent entity framework core?

I have two table like this -
public class Job
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime AddedTime { get; set; } = DateTime.Now;
public DateTime LastEdit { get; set; } = DateTime.Now;
public string Explanation { get; set; }
public string PhotoString { get; set; }
public bool isActive { get; set; } = true;
public int CompanyId { get; set; }
public Company Company { get; set; }
}
and company -
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Explanation { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string PhotoString { get; set; }
public bool isActive { get; set; } = true;
public int AppUserId { get; set; }
public AppUser AppUser { get; set; }
public List<Job> Jobs { get; set; }
}
I only want to get AppUserId from Company and all Jobs from every Company. I tried this and it gave me error.
using var context = new SocialWorldDbContext();
return await context.Jobs.Where(I => I.isActive == true && I.Company.isActive).Include(I=>I.Company.AppUserId).ToListAsync();
So my question is there any way I can get this data from parent?
Include adds whole entities to the output. To add just one property use Select, something like
context.Jobs
.Where(I => I.isActive == true && I.Company.isActive)
.Select(e => new {Job=e, CompanyAppUserId = e.Company.AppUserId})
.ToListAsync();

Updating entity tree with deep nested entities

My app deals with saving orders received from an external system. The order contains child items like line items, address, fulfillments, refunds > refund items etc.
Currently, I use an ugly looking code to detect what has changed in each entity by its External Id. Can someone recommend me a better way? :)
Following is a simplified entity model of Order
public class Order
{
public long Id { get; set; }
public string ExternalOrderId { get; set; }
public List<LineItem> LineItems { get; set; }
public List<Fulfillment> Fulfillments { get; set; }
public ShippingAddress ShippingAddress { get; set; }
public List<Refund> Refunds { get; set; }
public string FinancialStatus { get; set; }
public string FulfillmentStatus { get; set; }
}
public class LineItem
{
public long Id { get; set; }
public string ExternalLineItemId { get; set; }
public string SKU { get; set; }
public int Quantity { get; set; }
public long OrderId { get; set; }
}
public class Fulfillment
{
public long Id { get; set; }
public string ExternalFulfillmentId { get; set; }
public string Status { get; set; }
public string TrackingUrl { get; set; }
public long OrderId { get; set; }
}
public class ShippingAddress
{
public long Id { get; set; }
public string ExternalShippingAddressrId { get; set; }
public string Addres { get; set; }
public long OrderId { get; set; }
}
public class Refund
{
public long Id { get; set; }
public string ExternalRefundId { get; set; }
public List<RefundedItem> LineItems { get; set; }
public string CancelledReason { get; set; }
public long OrderId { get; set; }
}
public class RefundedItem
{
public long Id { get; set; }
public string ExternalRefundedItemId { get; set; }
public string SKU { get; set; }
public int Quantity { get; set; }
}
My sample code:
private async Task ManageFulfillments(long orderId, Order order)
{
if (order.Fulfillments == null || !order.Fulfillments.Any()) return;
var newFulfillmentIds = order.Fulfillments.Select(c => c.ExternalFulfillmentId).ToList();
var dbFulfillments = await _fulfillmentRepository.GetAll().IgnoreQueryFilters()
.Where(c => c.OrderId == orderId)
.Select(c => new { c.Id, c.ExternalFulfillmentId }).ToListAsync();
var dbFulfillmentIds = dbFulfillments.Select(c => c.ExternalFulfillmentId).ToList();
// Delete Fulfillments that are not present in new Fulfillments list
var deletedFulfillments = dbFulfillmentIds.Except(newFulfillmentIds).ToList();
if (deletedFulfillments.Any())
{
await _fulfillmentRepository.DeleteAsync(c =>
deletedFulfillments.Contains(c.ExternalFulfillmentId) && c.ExternalOrderId == orderId);
}
// Update existing Fulfillments ids
order.Fulfillments
.Where(c => dbFulfillmentIds.Contains(c.ExternalFulfillmentId))
.ToList()
.ForEach(async c =>
{
c.Id = dbFulfillments.Where(p => p.ExternalFulfillmentId == c.ExternalFulfillmentId)
.Select(p => p.Id).FirstOrDefault();
await _fulfillmentRepository.UpdateAsync(c);
});
// New Fulfillments will automatically be added by EF
}
I have similar code in place to update other entites as well and I'm not proud of it!

Dbcontext creating columns that I never made

I'm trying to create a view, which previously got an ID, which is working fine(checked in debugger, ID is correct), to invoke a method:
public ActionResult DetaljiNarudzbe(int id)
{
DetaljiNarudzbeViewModel model = new DetaljiNarudzbeViewModel();
model.Narudzba = ctx.Naruzbee.Where(x => x.Id == id).First();
model.StatusNarudzbe = ctx.StatusiNarudzbi.Where(x => x.Id == model.Narudzba.StatusNarudzbeId).FirstOrDefault();
model.Primaoc = ctx.Primaoci.Where(x => x.Id == model.Narudzba.PrimaocId).FirstOrDefault();
model.Adresa = ctx.Adrese.Where(x => x.Id == model.Narudzba.AdresaId).FirstOrDefault();
model.Grad = ctx.Gradovi.Where(x => x.Id == model.Adresa.GradId).FirstOrDefault();
model.StavkeNarudzbe = ctx.StavkeNarudzbi.Where(x => x.Narudzbe_Id == id).ToList();
model.Klijent = ctx.Klijenti.Where(x => x.Id == model.Narudzba.KlijentId).FirstOrDefault();
model.Korisnik = ctx.Korisnici.Where(x => x.Id == model.Klijent.KorisnikId).FirstOrDefault();
return View("DetaljiNarudzbe", model);
}
However, it keeps crashing at this part
model.StavkeNarudzbe = ctx.StavkeNarudzbi.Where(x => x.Narudzbe_Id == id).ToList();
It throws an exception, because for some reason, I think the context created another column called Narudzbe_Id1, which can't be null.
https://imgur.com/a/UFxXB - Image of the given exception
Further proof that it's an issue with dbcontext:
https://imgur.com/a/KEOe3
The extra column doesn't appear in the database on the SQL server's side, where I'm getting the data from.
If it helps, I'm posting the other relevant classes below:
public class StavkaNarudzbe : IEntity
{
public int Id { get; set; }
public bool IsDeleted { get; set; }
public string Naziv { get; set; }
public int Tezina { get; set; }
public double Cijena { get; set; }
public int Narudzbe_Id { get; set; }
public virtual Narudzbe Narudzbe { get; set; }
}
public class MojKontekst : DbContext
{
public MojKontekst() : base("DostavaConnString")
{
}
public DbSet<Adresa> Adrese { get; set; }
public DbSet<Grad> Gradovi { get; set; }
public DbSet<DetaljiVozila> DetaljiVozilaa { get; set; }
public DbSet<Klijent> Klijenti { get; set; }
public DbSet<Korisnik> Korisnici { get; set; }
public DbSet<Kurir> Kuriri { get; set; }
public DbSet<Kvar> Kvarovi { get; set; }
public DbSet<Obavijest> Obavijesti { get; set; }
public DbSet<Narudzbe> Naruzbee { get; set; }
public DbSet<Posiljka> Posiljke { get; set; }
public DbSet<Prelazi> Prelazii { get; set; }
public DbSet<Primaoc> Primaoci { get; set; }
public DbSet<Skladiste> Skladista { get; set; }
public DbSet<StatusNarudzbe> StatusiNarudzbi { get; set; }
public DbSet<StavkaNarudzbe> StavkeNarudzbi { get; set; }
public DbSet<Vozilo> Vozila { get; set; }
public DbSet<VrstaVozila> VrsteVozila { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public class DetaljiNarudzbeViewModel
{
public Klijent Klijent;
public Korisnik Korisnik;
public Narudzbe Narudzba;
public List<StavkaNarudzbe> StavkeNarudzbe;
public StatusNarudzbe StatusNarudzbe;
public Primaoc Primaoc;
public Adresa Adresa;
public Grad Grad;
}
public class Narudzbe : IEntity
{
public int Id { get; set; }
public bool IsDeleted { get; set; }
public string SifraNarudzbe { get; set; }
public DateTime DatumNarudzbe { get; set; }
public bool Osigurano { get; set; }
public bool BrzaDostava { get; set; }
public int BrojPaketa { get; set; }
public int KlijentId { get; set; }
public virtual Klijent Klijent { get; set; }
public int AdresaId { get; set; }
public virtual Adresa Adresa { get; set; }
public Nullable<int> PosiljkaId { get; set; }
public virtual Posiljka Posiljka { get; set; }
public int StatusNarudzbeId { get; set; }
public virtual StatusNarudzbe StatusNarudzbe{ get; set; }
public int PrimaocId { get; set; }
public virtual Primaoc Primaoc { get; set; }
public Nullable<System.DateTime> VrijemeIsporuke { get; set; }
public int CijenaNarudzbe { get; set; }
}
Exception Text: Invalid column name Narudzbe_Id1
This is Entity Framework trying to follow it's standard naming conventions for relationship columns.
See: https://msdn.microsoft.com/en-us/library/jj819164(v=vs.113).aspx for more information this.
As you are using non-standard names for your foreign key columns (i.e. Narudzbe_Id should be NarudzbeId) you'll need to let EF know how to link up your models. Either rename the properties of your classes to follow this naming convention, or use Data Annotations to explicitly tell EF about your relationships.
For example, try adding a ForeignKey attribute (found in the System.Componentmodel.Dataannotations.Schema namespace) like so:
public class StavkaNarudzbe : IEntity
{
public int Id { get; set; }
public bool IsDeleted { get; set; }
public string Naziv { get; set; }
public int Tezina { get; set; }
public double Cijena { get; set; }
public int Narudzbe_Id { get; set; }
[ForeignKey("Narudzbe_Id")]
public virtual Narudzbe Narudzbe { get; set; }
}

MVC How to count records in related Models?

I have two models, First is Relations, which is opened with Date, second model is Reservations, now i need to count record in reservations which have choiced Date of Relations. The tables is in Relationship relID from first i record in second table in DatumRID.
How to count records in Reservations which is related by ID to Relations
Model Relations:
public tbl_relacii()
{
tbl_rezervacii = new HashSet<tbl_rezervacii>();
}
[Key]
public int relID { get; set; }
[Column(TypeName = "date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime DatumR { get; set; }
public int sedista { get; set; }
public string vozilo { get; set; }
[StringLength(50)]
public string shofer1 { get; set; }
[StringLength(50)]
public string shofer2 { get; set; }
public string noteR { get; set; }
public virtual ICollection<tbl_rezervacii> tbl_rezervacii { get; set; }
public string DatumForDisplay
{
get
{
return DatumR.ToString("d");
}
}
Model Reservations:
public partial class tbl_rezervacii
{
[Key]
public int rID { get; set; }
public int AgentID { get; set; }
[StringLength(10)]
public string karta_br { get; set; }
public int DatumRID { get; set; }
public int patnikID { get; set; }
public int stanicaOD { get; set; }
public int stanicaDO { get; set; }
public decimal cena { get; set; }
public bool povratna { get; set; }
public DateTime? DatumP { get; set; }
public string noteP { get; set; }
public virtual tbl_agenti tbl_agenti { get; set; }
public virtual tbl_patnici tbl_patnici { get; set; }
public virtual tbl_relacii tbl_relacii { get; set; }
public virtual tbl_stanici tbl_stanici { get; set; }
public virtual tbl_stanici tbl_stanici1 { get; set; }
public string relacija
{
get
{
return tbl_stanici.stanica + "=>" + tbl_stanici1.stanica;
}
}
public string relacijaP
{
get
{
return tbl_stanici.stanica + "=>" + tbl_stanici1.stanica + "=>" + tbl_stanici.stanica;
}
}
}
And here is Controller for Relations Index:
public ActionResult Index()
{
return View(db.tbl_relacii.ToList().OrderByDescending(x => x.DatumR));
}
How to count records in Reservations then put Number of records to index of Relations?
I solved simply. In relations model i added just this:
public int Count
{
get
{
return tbl_rezervacii.Count;
}
}
And problem is Solved. Thank you
I think you can achieve using LINQ query. Please find the sample below.
var q = from d in Model.Reservations
select new Relations
{
Count = d.Reservations.Count()
};

Categories

Resources