I have read a lot of posts and some helped me, but I still have a stackoverflow on a one-to-one relation (between Employe and Adresse) defined with Entity framework 6 fluent.
The error appears on AdresseDTO when I create a new instance of a ViewModel wich contains some DTOs.
My plain objects
public class Personne
{
public int id { get; set; }
public string civ { get; set; }
public string nom { get; set; }
public string prenom { get; set; }
public string email { get; set; }
public string tel1 { get; set; }
public string tel2 { get; set; }
public Boolean isFournisseur { get; set; }
public Boolean isClient { get; set; }
public Boolean isDeleted { get; set; }
public virtual Adresse adresse { get; set; }
public virtual Utilisateur utilisateur { get; set; }
public Personne()
{
}
}
public class Employe : Personne
{
public virtual TEmploye typeEmploye { get; set; }
public virtual List<AffectationService> affectationServices { get; set; }
public Employe()
{
}
}
public class AffectationService
{
public int id { get; set; }
public virtual Employe employe { get; set; }
public virtual Service service { get; set; }
public virtual Droit groupe { get; set; }
public Boolean isPrincipal { get; set; }
}
public class TEmploye
{
public int id { get; set; }
public string libe { get; set; }
public TEmploye()
{
}
}
public class Adresse
{
public int id { get; set; }
public string numRue { get; set; }
public string nomRue { get; set; }
public string codePostal { get; set; }
public string ville { get; set; }
public string pays { get; set; }
public virtual Personne personne { get; set; }
public Adresse()
{
}
}
My DTOs
public class PersonneDTO
{
public int id { get; set; }
public bool isDeleted { get; set; }
public string civ { get; set; }
public string nom { get; set; }
public string prenom { get; set; }
public string email { get; set; }
public string tel1 { get; set; }
public string tel2 { get; set; }
public AdresseDTO adresse { get; set; }
public UtilisateurDTO utilisateur { get; set; }
public PersonneDTO()
{
adresse = new AdresseDTO();
utilisateur = new UtilisateurDTO();
}
}
public class EmployeDTO : PersonneDTO
{
public virtual TEmployeDTO typeEmploye { get; set; }
public virtual List<AffectationServiceDTO> affectationServices { get; set; }
public EmployeDTO()
{
affectationServices = new List<AffectationServiceDTO>();
typeEmploye = new TEmployeDTO();
}
}
public class TEmployeDTO
{
public int id { get; set; }
public string libe { get; set; }
public TEmployeDTO()
{
}
}
public class AffectationServiceDTO
{
public int id { get; set; }
public virtual EmployeDTO employe { get; set; }
public virtual ServiceDTO service { get; set; }
public virtual DroitDTO groupe { get; set; }
public Boolean isPrincipal { get; set; }
public AffectationServiceDTO()
{
service = new ServiceDTO();
groupe = new DroitDTO();
employe = new EmployeDTO();
}
}
public class AdresseDTO
{
public int id { get; set; }
public string numRue { get; set; }
public string nomRue { get; set; }
public string codePostal { get; set; }
public string ville { get; set; }
public string pays { get; set; }
public AdresseDTO()
{
}
}
How I mapp my DTOs with the plain objects
//DomainToViewModel
CreateMap<Adresse, AdresseDTO>().MaxDepth(1);
CreateMap<Personne, PersonneDTO>().MaxDepth(1);
CreateMap<Employe, EmployeDTO>().MaxDepth(1);
CreateMap<AffectationService, AffectationServiceDTO>().MaxDepth(1);
CreateMap<TEmploye, TEmployeDTO>().MaxDepth(1);
//ViewModelToDomain
CreateMap<AdresseDTO, Adresse>().MaxDepth(1)
.ForMember(g => g.id, map => map.MapFrom(vm => vm.id))
.ForMember(g => g.codePostal, map => map.MapFrom(vm => vm.codePostal))
.ForMember(g => g.nomRue, map => map.MapFrom(vm => vm.nomRue))
.ForMember(g => g.numRue, map => map.MapFrom(vm => vm.numRue))
.ForMember(g => g.pays, map => map.MapFrom(vm => vm.pays))
.ForMember(g => g.ville, map => map.MapFrom(vm => vm.ville));
CreateMap<UtilisateurDTO, Utilisateur>().MaxDepth(1)
.ForMember(g => g.id, map => map.MapFrom(vm => vm.id))
.ForMember(g => g.dConnexion, map => map.MapFrom(vm => vm.dConnexion))
.ForMember(g => g.dCreation, map => map.MapFrom(vm => vm.dCreation))
.ForMember(g => g.isActive, map => map.MapFrom(vm => vm.isActive))
.ForMember(g => g.isDeleted, map => map.MapFrom(vm => vm.isDeleted))
.ForMember(g => g.login, map => map.MapFrom(vm => vm.login))
.ForMember(g => g.password, map => map.MapFrom(vm => vm.password))
.ForMember(g => g.personne, map => map.MapFrom(vm => vm.personne)).MaxDepth(1);
CreateMap<EmployeDTO, Employe>().MaxDepth(1)
.ForMember(g => g.id, map => map.MapFrom(vm => vm.id))
.ForMember(g => g.typeEmploye, map => map.MapFrom(vm => vm.typeEmploye))
.ForMember(g => g.affectationServices, map => map.MapFrom(vm => vm.affectationServices))
.ForMember(g => g.utilisateur, map => map.MapFrom(vm => vm.utilisateur)).MaxDepth(1)
.ForMember(g => g.adresse, map => map.MapFrom(vm => vm.adresse)).MaxDepth(1);
CreateMap<TEmployeDTO, TEmploye>().MaxDepth(1)
.ForMember(g => g.libe, map => map.MapFrom(vm => vm.libe));
CreateMap<AffectationServiceDTO, AffectationService>().MaxDepth(1)
.ForMember(g => g.id, map => map.MapFrom(vm => vm.id))
.ForMember(g => g.employe, map => map.MapFrom(vm => vm.employe)).MaxDepth(1)
.ForMember(g => g.groupe, map => map.MapFrom(vm => vm.groupe)).MaxDepth(1)
.ForMember(g => g.isPrincipal, map => map.MapFrom(vm => vm.isPrincipal))
.ForMember(g => g.service, map => map.MapFrom(vm => vm.service)).MaxDepth(1);
Mapping with EF6 fluent
public PersonneConfiguration()
{
ToTable("Personne");
HasKey<int>(a => a.id);
HasRequired<Adresse>(x => x.adresse);
HasOptional<Utilisateur>(x => x.utilisateur);
Property(a => a.civ).HasColumnType("varchar").HasMaxLength(3);
Property(a => a.nom).HasColumnType("varchar").HasMaxLength(80);
Property(a => a.prenom).HasColumnType("varchar").HasMaxLength(80);
Property(a => a.email).HasColumnType("varchar").HasMaxLength(150);
Property(a => a.tel1).HasColumnType("varchar").HasMaxLength(10);
Property(a => a.tel2).HasColumnType("varchar").HasMaxLength(10);
Property<bool>(a => a.isClient);
Property<bool>(a => a.isFournisseur);
Property<bool>(a => a.isDeleted);
}
public EmployeConfiguration()
{
ToTable("Employe");
HasKey<int>(a => a.id);
HasOptional<TEmploye>(x => x.typeEmploye);
Property<bool>(a => a.isDeleted);
}
public AdresseConfiguration()
{
ToTable("Adresse");
HasKey<int>(a => a.id);
Property(a => a.codePostal).HasColumnType("varchar").HasMaxLength(5);
Property(a => a.nomRue).HasColumnType("varchar").HasMaxLength(150);
Property(a => a.numRue).HasColumnType("varchar").HasMaxLength(10);
Property(a => a.ville).HasColumnType("varchar").HasMaxLength(80);
Property(a => a.pays).HasColumnType("varchar").HasMaxLength(80);
}
public AffectationServiceConfiguration()
{
ToTable("AffectationService");
HasKey<int>(a => a.id);
HasRequired<Employe>(x => x.employe).WithMany(x => x.affectationServices);
HasRequired<Service>(x => x.service);
HasRequired<Droit>(x => x.groupe);
Property<bool>(a => a.isPrincipal);
}
public TEmployeConfiguration()
{
ToTable("TEmploye");
HasKey<int>(a => a.id);
Property(a => a.libe).HasColumnType("varchar").HasMaxLength(100);
}
And the ViewModel taht causes the error
public class EditEmployeViewModel
{
public EmployeDTO personne { get; set; }
public EditEmployeViewModel()
{
personne = new EmployeDTO();
}
}
The stackoverflow occurs when a create a new EmployeDTO(). I tried to solve this by adding .MaxDepth(1) where it's possible, but it doesn't work...
Sorry guys, I know that is a long post, but I don't have any idea about my problem so I try to show you the most relevent part of my code.
Thank you for all, I'm brand new in EF6 so if you have any tips or good pratices to share it will be a pleasure.
thank you for your help.
I didnt' find a real solution so I removed the refererence Personne in my object Adresse to avoid the stackoverflow exception...
Related
I have a class Affaire, containing Secteurs, containing associated Emplacements, and corresponding DTO objects to transform. I use AutoMapper for that.
public class Affaire
{
public string Nom { get; set; }
public class Emplacement
{
public int AffaireId { get; set; }
public Affaire Affaire { get; set; }
public class EmplacementDTO
{
public int AffaireId { get; set; }
public string AffaireNom { get; set; }
The Emplacements are grouped in Secteur, having as well its Affaire
public class Secteur
{
public int AffaireId { get; set; }
public Affaire Affaire { get; set; }
public IList<Emplacement> Emplacements { get; set; } = new List<Emplacement>();
When I map from Emplacement to a EmplacementDTO I don't want to include Affaire, only AffaireId:
CreateMap<Emplacement, EmplacementDTO>()
.ForMember(dto => dto.AffaireId, o => o.MapFrom(dto => dto.Affaire.Id))
.ForMember(dto => dto.AffaireNom, o => o.MapFrom(dto => dto.Affaire.Nom))
.ReverseMap()
.ForPath(bo => bo.Affaire, o => o.MapFrom(dto => (Affaire)null)); // <<<< HERE
This configuration does not seem to work when Emplacement is embedded in a container SecteurDTO, however, for the container itself, the configurartion seem to work (its Affaire is set to null):
CreateMap<Secteur, SecteurDTO>()
.ForMember(dto => dto.AffaireId, o => o.MapFrom(dto => dto.Affaire.Id))
.ForMember(dto => dto.AffaireNom, o => o.MapFrom(dto => dto.Affaire.Nom))
.ReverseMap()
.ForPath(bo => bo.Affaire, o => o.MapFrom(dto => (Affaire)null))
related problem here
Here is the working demo in my project:
Model:
public class Affaire
{
public int Id { get; set; }
public string Nom { get; set; }
public IList<Emplacement> Emplacements { get; set; } = new List<Emplacement>();
}
public class Emplacement
{
public int AffaireId { get; set; }
public Affaire Affaire { get; set; }
}
public class Secteur
{
public int AffaireId { get; set; }
public Affaire Affaire { get; set; }
public IList<Emplacement> Emplacements { get; set; } = new List<Emplacement>();
}
DTO:
public class EmplacementDTO
{
public int AffaireId { get; set; }
public string AffaireNom { get; set; }
public Affaire Affaire { get; set; }
}
public class SecteurDTO
{
public int AffaireId { get; set; }
public string AffaireNom { get; set; }
public Affaire Affaire { get; set; }
public IList<EmplacementDTO> Emplacements { get; set; }
}
Profile:
public class YourProfile : Profile
{
public YourProfile()
{
CreateMap<Emplacement, EmplacementDTO>()
.ForMember(dto => dto.AffaireId, o => o.MapFrom(dto => dto.Affaire.Id))
.ForMember(dto => dto.AffaireNom, o => o.MapFrom(dto => dto.Affaire.Nom))
.ReverseMap()
.ForPath(bo => bo.Affaire, o => o.MapFrom(dto => (Affaire)null));
CreateMap<Secteur, SecteurDTO>()
.ForMember(dto => dto.AffaireId, o => o.MapFrom(dto => dto.Affaire.Id))
.ForMember(dto => dto.AffaireNom, o => o.MapFrom(dto => dto.Affaire.Nom))
.ReverseMap()
.ForPath(bo => bo.Affaire, o => o.MapFrom(dto => (Affaire)null));
}
}
Backend testing code:
public List<EmployeeModel> Index(List<SecteurDTO> dto)
{
dto = new List<SecteurDTO>()
{
new SecteurDTO(){
AffaireId=1,
AffaireNom="aaa",
Emplacements = new List<EmplacementDTO>()
{
new EmplacementDTO(){AffaireId=1,Affaire=new Affaire(){Id=1,Nom="aa"}}
},
Affaire=new Affaire(){
Id=1,
Nom="aaa",
Emplacements=new List<Emplacement>()
{
new Emplacement(){AffaireId=1,Affaire=new Affaire(){Id=1,Nom="aa"}}
}
}
}
};
var bo= new List<Secteur>() { };
var mapper = _mapper.Map(dto, bo);
//...
}
Result:
I'm getting the error
Multiplicity constraint violated. The role 'CollectionSite_CollectionSiteOption_Target' of the relationship 'DatabaseRefreshRecovery.Data.CollectionSite_CollectionSiteOption' has multiplicity 1 or 0..1.
and I can't figure out what is the cause.
From the Google results I found, it seems that this error is associated with updating a detached entity. I'm doing neither. I'm getting this error while retrieving data from the database.
I'm using EF6 in a desktop application. The entities are a one-to-one relationship where the SiteID serves as the primary key in the parent table (CollectionSite) and the primary and foreign key in the child table (CollectionSiteOption).
Below are my classes, line of code causing the error, and the context portion for the classes. Does anyone see anything I may have missed or any idea what may be going on?
CollectionSite class:
namespace DatabaseRefreshRecovery.Models
{
public class CollectionSite
{
public CollectionSite()
{
AlereSites = new List<AlereSite>();
AtnSites = new List<AtnSite>();
ClientCollSites = new List<ClientCollSite>();
CollectionSiteCarriers = new List<CollectionSiteCarrier>();
//CollectionSiteExtra = new CollectionSiteExtra();
CollectionSiteGroups = new List<CollectionSiteGroups>();
ClinicAttributesAssignments = new List<ClinicAttributesAssignment>();
CollectionSiteMultiples = new List<CollectionSiteMultiple>();
CollectionSiteOption = new CollectionSiteOption();
CollectionSitePanels = new List<CollectionSitePanel>();
CrlSites = new List<CrlSite>();
CsAddresses = new List<CsAddress>();
//HoursOfOperation = new HoursOfOperation();
ReimbursementHistories = new List<ReimbursementHistory>();
SiteDynamicServices = new List<SiteDynamicService>();
SiteServicesAndPrices = new List<SiteServicesAndPrice>();
UserProfiles = new List<UserProfile>();
}
[Key]
public int SiteID { get; set; }
public string Sitestate { get; set; }
public int Machid { get; set; }
public short Labpsc { get; set; }
public string Labid { get; set; }
public string AmexId { get; set; }
public string Payaccount { get; set; }
public string Ratingid { get; set; }
public short Active { get; set; }
public string Comments { get; set; }
public string Privatecomments { get; set; }
public string Name { get; set; }
public int? Mroid { get; set; }
public int? Datamgmt { get; set; }
public int? Internalsite { get; set; }
public int? Testsite { get; set; }
public Guid MsreplTranVersion { get; set; }
public int? Taxexempsig { get; set; }
public int? Reportinghold { get; set; }
public int? Orderhold { get; set; }
public int Backgroundsallowed { get; set; }
public bool AllowPsychemedicsHairTestingForClinicsClients { get; set; }
public bool IncludeInLabAccountSync { get; set; }
public bool AllowSsnsearch { get; set; }
public bool Electronicdotallowed { get; set; }
public bool ClinicOptedInForRandomsProgram { get; set; }
public bool? Clinicuploadenabled { get; set; }
public int ServiceQueueTypeId { get; set; }
public int FrontOfficeCheckInGroupMode { get; set; }
public bool Advancedsearch123allowed { get; set; }
public bool? IsLabFriendly { get; set; }
public string LabCorpSupplyId { get; set; }
public string LabCorpSupplyPhoneNumber { get; set; }
public string LabCorpCourierPhoneNumber { get; set; }
public virtual List<AlereSite> AlereSites { get; set; }
public virtual List<AtnSite> AtnSites { get; set; }
public virtual List<ClientCollSite> ClientCollSites { get; set; }
public virtual List<CollectionSiteCarrier> CollectionSiteCarriers { get; set; }
//public virtual CollectionSiteExtra CollectionSiteExtra { get; set; }
public virtual List<CollectionSiteGroups> CollectionSiteGroups { get; set; }
public virtual List<CollectionSiteMultiple> CollectionSiteMultiples { get; set; }
public virtual List<ClinicAttributesAssignment> ClinicAttributesAssignments { get; set; }
public virtual CollectionSiteOption CollectionSiteOption { get; set; }
public virtual List<CollectionSitePanel> CollectionSitePanels { get; set; }
public virtual List<CrlSite> CrlSites { get; set; }
public virtual List<CsAddress> CsAddresses { get; set; }
//public virtual HoursOfOperation HoursOfOperation { get; set; }
public virtual List<ReimbursementHistory> ReimbursementHistories { get; set; }
public virtual List<SiteDynamicService> SiteDynamicServices { get; set; }
public virtual List<SiteServicesAndPrice> SiteServicesAndPrices { get; set; }
public virtual List<UserProfile> UserProfiles { get; set; }
}
}
CollectionSiteOption class:
namespace DatabaseRefreshRecovery.Models
{
public class CollectionSiteOption
{
[Key, ForeignKey("CollectionSite")]
public int Siteid { get; set; }
public string Attainbilltonum { get; set; }
public int? Posonlyreviewcontract { get; set; }
public int? Backgroundscontract { get; set; }
public int? _24hours { get; set; }
public int? Averifycontract { get; set; }
public string Connectiontype { get; set; }
public string Ispnumber { get; set; }
public string Userid { get; set; }
public string Password { get; set; }
public Guid MsreplTranVersion { get; set; }
public DateTime? CliaExpirationDate { get; set; }
[XmlIgnore]
public virtual CollectionSite CollectionSite { get; set; }
}
}
DBContext for CollectionSite:
public DbSet<CollectionSite> CollectionSites { get; set; }
Fluent API...
//
modelBuilder.Entity<CollectionSite>().ToTable("COLLECTIONSITE");
modelBuilder.Entity<CollectionSite>().Property(p => p.MsreplTranVersion).HasColumnName("msrepl_tran_version");
modelBuilder.Entity<CollectionSite>().Property(p => p.SiteID).HasColumnName("SITEID");
modelBuilder.Entity<CollectionSite>().Property(p => p.AmexId).HasColumnName("AMEX_ID");
modelBuilder.Entity<CollectionSite>().Property(p => p.MsreplTranVersion).HasColumnName("msrepl_tran_version");
modelBuilder.Entity<CollectionSite>().HasMany<ClinicAttributesAssignment>(x => x.ClinicAttributesAssignments).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.SiteId);
modelBuilder.Entity<CollectionSite>().HasMany<AlereSite>(x => x.AlereSites).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.SiteId);
modelBuilder.Entity<CollectionSite>().HasMany<AtnSite>(x => x.AtnSites).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.Siteid);
modelBuilder.Entity<CollectionSite>().HasMany<ClientCollSite>(x => x.ClientCollSites).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.Siteid);
modelBuilder.Entity<CollectionSite>().HasMany<CollectionSiteCarrier>(x => x.CollectionSiteCarriers).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.SiteID);
//modelBuilder.Entity<CollectionSite>().HasOptional<CollectionSiteExtra>(x => x.CollectionSiteExtra).WithRequired(x => x.CollectionSite);
modelBuilder.Entity<CollectionSite>().HasMany<CollectionSiteMultiple>(x => x.CollectionSiteMultiples).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.Siteid);
modelBuilder.Entity<CollectionSite>().HasOptional<CollectionSiteOption>(x => x.CollectionSiteOption).WithRequired(x => x.CollectionSite);
modelBuilder.Entity<CollectionSite>().HasMany<CollectionSitePanel>(x => x.CollectionSitePanels).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.SiteId);
modelBuilder.Entity<CollectionSite>().HasMany<CrlSite>(x => x.CrlSites).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.Siteid);
modelBuilder.Entity<CollectionSite>().HasMany<CsAddress>(x => x.CsAddresses).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.Siteid);
modelBuilder.Entity<CollectionSite>().HasMany<ReimbursementHistory>(x => x.ReimbursementHistories).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.SiteId);
modelBuilder.Entity<CollectionSite>().HasMany<SiteDynamicService>(x => x.SiteDynamicServices).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.SiteId);
modelBuilder.Entity<CollectionSite>().HasMany<SiteServicesAndPrice>(x => x.SiteServicesAndPrices).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.Siteid);
modelBuilder.Entity<CollectionSite>().HasMany<UserProfile>(x => x.UserProfiles).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.Siteid);
//modelBuilder.Entity<CollectionSite>().HasOptional<HoursOfOperation>(x => x.HoursOfOperation).WithRequired(x => x.CollectionSite);
modelBuilder.Entity<CollectionSite>().HasMany<CollectionSiteGroups>(x => x.CollectionSiteGroups).WithRequired(x => x.CollectionSite).HasForeignKey(x => x.Siteid);
DBContext for CollectionSiteOption:
public DbSet<CollectionSiteOption> CollectionSiteOptions { get; set; }
Fluent API...
//
modelBuilder.Entity<CollectionSiteOption>().HasKey(e => e.Siteid);
modelBuilder.Entity<CollectionSiteOption>().ToTable("COLLECTIONSITEOPTIONS", "dbo");
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Siteid).HasColumnName("SITEID");
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Attainbilltonum)
.HasColumnName("ATTAINBILLTONUM")
.HasMaxLength(15)
.IsUnicode(false);
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Averifycontract).HasColumnName("AVERIFYCONTRACT");
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Backgroundscontract).HasColumnName("BACKGROUNDSCONTRACT");
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.CliaExpirationDate).HasColumnType("datetime");
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Connectiontype)
.HasColumnName("CONNECTIONTYPE")
.HasMaxLength(30)
.IsUnicode(false);
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Ispnumber)
.HasColumnName("ISPNUMBER")
.HasMaxLength(10)
.IsUnicode(false);
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.MsreplTranVersion).HasColumnName("msrepl_tran_version");
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Password)
.HasColumnName("PASSWORD")
.HasMaxLength(10)
.IsUnicode(false);
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Posonlyreviewcontract).HasColumnName("POSONLYREVIEWCONTRACT");
modelBuilder.Entity<CollectionSiteOption>().Property(e => e.Userid)
.HasColumnName("USERID")
.HasMaxLength(30)
.IsUnicode(false);
modelBuilder.Entity<CollectionSiteOption>().Property(e => e._24hours).HasColumnName("24HOURS");
Method of offending code:
I prefixed the offending line of code with a *---> and <---* after it.
private CollectionSite GetCollectionSiteInformation(int siteID)
{
CollectionSite collectionSite = new CollectionSite();
SendMessageToUser($"Retrieving the collection site for '{siteID}'.");
collectionSite = Context.CollectionSites.Where(o => o.SiteID == siteID).SingleOrDefault();
SendMessageToUser($"Retrieving the clinic attribute assignments & value assignments for '{siteID}'.");
collectionSite.ClinicAttributesAssignments = Context.ClinicAttributesAssignment.Where(x => x.SiteId == siteID).Include(x => x.ClinicAttributesValueAssignments).ToList();
SendMessageToUser($"Retrieving the Alere sites for '{siteID}'.");
collectionSite.AlereSites = Context.AlereSites.Where(x => x.SiteId == siteID).ToList();
SendMessageToUser($"Retrieving the Atn sites for '{siteID}'.");
collectionSite.AtnSites = Context.AtnSites.Where(x => x.Siteid == siteID).ToList();
SendMessageToUser($"Retrieving the client collection sites for '{siteID}'.");
collectionSite.ClientCollSites = Context.ClientCollSites.Where(x => x.Siteid == siteID).ToList();
SendMessageToUser($"Retrieving the collection site carrier for '{siteID}'.");
collectionSite.CollectionSiteCarriers = Context.CollectionSiteCarrier.Where(x => x.SiteID == siteID).ToList();
//SendMessageToUser($"Retrieving the collection site extras for '{siteID}'.");
//collectionSite.CollectionSiteExtra = Context.CollectionSiteExtras.Where(x => x.Siteid == siteID).SingleOrDefault();
SendMessageToUser($"Retrieving the collection site multiples for '{siteID}'.");
collectionSite.CollectionSiteMultiples = Context.CollectionSiteMultiples.Where(x => x.Siteid == siteID).ToList();
SendMessageToUser($"Retrieving the collection site groups for '{siteID}'.");
collectionSite.CollectionSiteGroups = Context.CollectionSiteGroups.Where(x => x.Siteid == siteID).ToList();
SendMessageToUser($"Retrieving the collection site options for '{siteID}'.");
*--->collectionSite.CollectionSiteOption = Context.CollectionSiteOptions.Where(x => x.Siteid == siteID).SingleOrDefault();<---*
SendMessageToUser($"Retrieving the collection site panels for '{siteID}'.");
collectionSite.CollectionSitePanels = Context.CollectionSitePanels.Where(x => x.SiteId == siteID).ToList();
SendMessageToUser($"Retrieving the CRL sites for '{siteID}'.");
collectionSite.CrlSites = Context.CrlSites.Where(x => x.Siteid == siteID).ToList();
SendMessageToUser($"Retrieving the collection site addresses for '{siteID}'.");
collectionSite.CsAddresses = Context.CsAddresses.Where(x => x.Siteid == siteID).Include(x => x.Address).ToList();
SendMessageToUser($"Retrieving the reimbursement histories for '{siteID}'.");
collectionSite.ReimbursementHistories = Context.ReimbursementHistory.Where(x => x.SiteId == siteID).ToList();
SendMessageToUser($"Retrieving the site dynamic services for '{siteID}'.");
collectionSite.SiteDynamicServices = Context.SiteDynamicServices.Where(x => x.SiteId == siteID).ToList();
SendMessageToUser($"Retrieving the site services & prices for '{siteID}'.");
collectionSite.SiteServicesAndPrices = Context.SiteServicesAndPrices.Where(x => x.Siteid == siteID).ToList();
SendMessageToUser($"Retrieving the user profiles for '{siteID}'.");
collectionSite.UserProfiles = Context.UserProfiles.Where(x => x.Siteid == siteID).Include(x => x.Mach).ToList();
//SendMessageToUser($"Retrieving the hours of operation for '{siteID}'.");
//collectionSite.HoursOfOperation = Context.HoursOfOperation.Where(x => x.Siteid == siteID).SingleOrDefault();
return collectionSite;
}
Stack trace:
at System.Data.Entity.Core.Objects.EntityEntry.WillNotRefSteal(EntityReference refToPrincipal, IEntityWrapper wrappedPrincipal)
at System.Data.Entity.Core.Objects.EntityEntry.FixupEntityReferenceToPrincipal(EntityReference relatedEnd, EntityKey foreignKey, Boolean setIsLoaded, Boolean replaceExistingRef)
at System.Data.Entity.Core.Objects.EntityEntry.FixupReferencesByForeignKeys(Boolean replaceAddedRefs, EntitySetBase restrictTo)
at System.Data.Entity.Core.Objects.ObjectStateManager.FixupReferencesByForeignKeys(EntityEntry newEntry, Boolean replaceAddedRefs)
at System.Data.Entity.Core.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
at DatabaseRefreshRecovery.Processess.Clinics.GetCollectionSiteInformation(Int32 siteID) in C:\development\escreen\DEV-TOOLS\DatabaseRefreshRecoveryTool\DatabaseRefreshRecovery\Processes\Clinics.cs:line 137
at DatabaseRefreshRecovery.Processess.Clinics.RetrieveUserData() in C:\development\escreen\DEV-TOOLS\DatabaseRefreshRecoveryTool\DatabaseRefreshRecovery\Processes\Clinics.cs:line 48
at DatabaseRefreshRecovery.DatabaseRefreshRecoveryForm.ProcessCollectionSites() in C:\development\escreen\DEV-TOOLS\DatabaseRefreshRecoveryTool\DatabaseRefreshRecovery\DatabaseRefreshRecoveryForm.cs:line 159
at DatabaseRefreshRecovery.DatabaseRefreshRecoveryForm.ProcessBackup() in C:\development\escreen\DEV-TOOLS\DatabaseRefreshRecoveryTool\DatabaseRefreshRecovery\DatabaseRefreshRecoveryForm.cs:line 88
Resolved my issue by adding the .Map() to define the foreign key. Thought the foreign key needed to be defined on one-to-one relationships but didn't know how and the example I found for one-to-one relationships through the API didn't have it defined.
modelBuilder.Entity<CollectionSite>().HasOptional<CollectionSiteOption>(x => x.CollectionSiteOption).WithRequired(x => x.CollectionSite).Map(x => x.MapKey("Siteid"));
I am using Entity Framework Core v3. I am currently trying to retrieve data from tables that contain a one-to-many relationship.
The tables here are PersonNote and PersonNoteAttachment.
One PersonNote can have many PersonNoteAttachments. Data is getting currently repeated. So if you see the result section it has Name appearing twice. This is just an example. I am not sure if I need to change the query or change the model structure etc. Could somebody help
PersonNote
Id Name
-------------
113 TestNote
PersonNoteAttachment
Id PersonNoteId Note
---------------------------------
101 113 Attachment1
102 113 Attachment2
Result
TestNote Attachment1
TestNote Attachment2
What I am looking at is
TestNote Attachment1
Attachment2
Query
public IQueryable<PersonNote> GetPersonNotes(int personId)
{
var personNotes = _context.PersonNotes
.Include(x => x.Person)
.Include(x => x.Author)
.Include(x => x.PersonNoteAttachment)
.Where(p => p.PersonId == personId)
.OrderByDescending(d => d.Created);
return personNotes;
}
Model
namespace Organisation.Models.DataModels
{
[Table(nameof(PersonNote), Schema = "common")]
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
[ForeignKey("PersonId")]
public Person Person { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
public PersonNoteAttachment PersonNoteAttachment { get; set; }
[ForeignKey("AuthorId")]
public Person Author { 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 class PersonNoteAttachment
{
public int Id { get; set; }
public int PersonNoteId { get; set; }
[ForeignKey("PersonNoteId")]
public PersonNote PersonNote { get; set; }
public string Alias { get; set; }
public string FileName { get; set; }
public string MimeType { get; set; }
public int Deleted { 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; }
}
Mapping
CreateMap<Organisation.Models.DataModels.PersonNote, Organisation.Models.User.PersonNote>()
.ForMember(t => t.Id, opt => opt.MapFrom(s => s.Id))
.ForMember(t => t.PersonId, opt => opt.MapFrom(s => s.PersonId))
.ForMember(t => t.AuthorName, opt => opt.MapFrom(s => s.Author.FirstName + " " + s.Author.LastName))
.ForMember(t => t.FileName, opt => opt.MapFrom(s => s.PersonNoteAttachment.FileName))
.ForMember(t => t.MimeType, opt => opt.MapFrom(s => s.PersonNoteAttachment.MimeType))
.ForMember(t => t.Alias, opt => opt.MapFrom(s => s.PersonNoteAttachment.Alias))
.ForMember(t => t.Note, opt => opt.MapFrom(s => s.Note))
.ForMember(t => t.AuthorId, opt => opt.MapFrom(s => s.AuthorId))
.ForMember(t => t.CreatedBy, opt => opt.MapFrom(s => s.CreatedBy))
.ForMember(t => t.Created, opt => opt.MapFrom(s => s.Created));
If you notice PersonNoteAttachment is not an array. If I make it an array, then the following changes would need to be done:
public PersonNoteAttachment[] PersonNoteAttachment { get; set; }
and in the mapping to avoid compile errors
.ForMember(t => t.FileName, opt => opt.MapFrom(s => s.PersonNoteAttachment[0].FileName))
API
[FunctionName(nameof(GetPersonNote))]
[UsedImplicitly]
public Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
int id) => _helper.HandleAsync(async () =>
{
// await _helper.ValidateRequestAsync(req, SecurityPolicies.ViewNotes);
var personNotes = await _organisationRepository.GetPersonNotes(id).ProjectTo<PersonNote>(_mapper.ConfigurationProvider).ToListAsync();
return new OkObjectResult(personNotes);
});
ViewModel
namespace Organisation.Models.User
{
[Table(nameof(PersonNote), Schema = "common")]
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 Alias { get; set; }
public string FileName { get; set; }
public string MimeType { get; set; }
public string AuthorName { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
}
}
Solution 1 - But with internal exception
Unable to cast object of type 'System.Boolean' to type 'System.Int32'.
Tried the following , which is providing the desired results . The postman returns 200k. Although debugging the code throwing an internal exception.
Added
Datamodel
namespace Organisation.Models.DataModels
{
public class PersonNote
{
public IEnumerable<PersonNoteAttachment> PersonNoteAttachment { get; set; }
}
}
Viewmodel
namespace Organisation.Models.User
{
[Table(nameof(PersonNote), Schema = "common")]
public class PersonNote
{
public IEnumerable<string> Alias { get; set; }
public IEnumerable<string> FileName { get; set; }
public IEnumerable<string> MimeType { get; set; }
}
}
Mapping
.ForMember(t => t.FileName, opt => opt.MapFrom(s => s.PersonNoteAttachment.Select(x=> x.FileName)))
.ForMember(t => t.MimeType, opt => opt.MapFrom(s => s.PersonNoteAttachment.Select(x => x.MimeType)))
.ForMember(t => t.Alias, opt => opt.MapFrom(s => s.PersonNoteAttachment.Select(x => x.Alias)))
Abduls solution
API
[FunctionName(nameof(GetPersonNote))]
[UsedImplicitly]
public Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
int id) => _helper.HandleAsync(async () =>
{
await _helper.ValidateRequestAsync(req, SecurityPolicies.ViewNotes);
var personNotes = _organisationRepository.GetPersonNotes(id);
//IEnumerable<PersonNote> personNotes = groupedNotes.Select(Profiles.GenistarUserProfile.MapGroupToPersonNote);
return new OkObjectResult(personNotes.ToList());
});
Repository
public IQueryable<Genistar.Organisation.Models.User.PersonNote> GetPersonNotes(int personId)
{
var personNotes = _context.PersonNotes
.Include(x => x.Person)
.Include(x => x.Author)
.Where(p => p.PersonId == personId).Select(x => new Genistar.Organisation.Models.User.PersonNote
{
//assign all properties
Attachments = _context.PersonNotesAttachments.Where(y => y.PersonNoteId == x.Id).Select(y => new Genistar.Organisation.Models.User.PersonNoteAttachment
{
FileName = y.FileName,
Alias = y.Alias,
MimeType = y.MimeType
}),
PersonId = x.PersonId,
AuthorName = x.Person.FirstName + " " + x.Person.LastName,
Note = x.Note,
Id = x.Id,
Created = x.Created
}).OrderByDescending(x=> x.Created).AsNoTracking();
return personNotes;
}
The following code will allow you to use a 3 layered architecture with your app, and try to reduce the coupling between your layers while keeping your existing structure.
To start, change your query:
public IQueryable<DataModel.PersonNote> GetPersonNotes(int personId)
{
var personNotes = _context.PersonNotes
.Include(x => x.Person)
.Include(x => x.Author)
.Where(p => p.PersonId == personId);
return personNotes;
}
And add another repo query:
public IQueryable<DataModel.PersonNoteAttachment> GetAttachments(int personNoteId)
{
var attachments = _context.PersonNotesAttachments.Where(x => x.Id == personNoteId);
return attachments ;
}
Use the following Models, PersonNote being your ViewModel:
namespace Organisation.Models.User
{
public class PersonNoteAttachment
{
public string Alias { get; set; }
public string FileName { get; set; }
public string MimeType { 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 IEnumerable<PersonNoteAttachment> Attachments { get; set; }
public string AuthorName { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
}
}
Now we create a new function in BL layer that will return your data for the ViewModel:
public IEnumerable<User.PersonNote> GetPersonNotesAndAttachments(int personID)
{
var personNotes = _organisationRepository.GetPersonNotes(id).Select(x =>
new User.PersonNote
{
//assign all properties
Attachments = _organisationRepository.GetAttachments(x.PersonNoteID).Select(y =>
new User.PersonNoteAttachment
{
FileName = y.FileName,
Alias = y.Alias,
MimeType = y.MimeType
}).AsEnumerable(),
PersonId = x.PersonId,
AuthorName = x.Person.FirstName + " " + x.Person.LastName,
Note = x.Note,
Id = x.Id,
Created = x.Created
});
return personNotes;
}
The IEnumerable<PersonNote> "What I am looking at is" can be accessed like this:
IEnumerable<User.PersonNote> personNotes = new BlClass().GetPersonNotesAndAttachments(id);
I'm looking for any how to or documentation about use of Embeddable with FluentNHibernate exactly with in the Hibernate. Does has any way to works with Embeddable in FluentNHibernate, if not has what's the best way to simulate this ?
Finally I found some solution. It's very simple like Embeddable of JPA/Hibernate.
Found here: https://github.com/jagregory/fluent-nhibernate/wiki/Fluent-mapping#components
Then I did.
public class Cliente {
public virtual long id { set; get; }
public virtual long codigo { set; get; }
public virtual String nome { set; get; }
public virtual String sexo { set; get; }
public virtual String cpf { set; get; }
public virtual String rg { set; get; }
public virtual DateTime dtNascimento { set; get; }
public virtual Endereco endereco { set; get; } //Embeddable
public Cliente() { }
}
public class Endereco {
public String endereco;
public String numero;
public String bairro;
public String complemento;
public String cidade;
public String cep;
public EstadosBrasil uf;
public Endereco() {
}
}
Mapping
public class ClienteMap : ClassMap<Cliente> {
public ClienteMap() {
Table("CLIENTE");
Id(c => c.id).GeneratedBy.Native();
Map(c => c.codigo);
Map(c => c.nome);
Map(c => c.sexo).Length(2);
Map(c => c.cpf);
Map(c => c.rg);
Map(c => c.dtNascimento).CustomType<DateTime>();
//embeddable
Component(c => c.endereco, e => {
e.Map(c => c.endereco);
e.Map(c => c.numero).CustomType<int>();
e.Map(c => c.bairro);
e.Map(c => c.complemento);
e.Map(c => c.cidade);
e.Map(c => c.cep);
e.Map(c => c.uf).CustomType<GenericEnumMapper<EstadosBrasil>>();
});
}
}
I have the following tables,
Product(pro_iIDX[PK], pro_sName)
Manufacturer(man_iIDX[PK], man_sName)
ProductManufacturer(pma_iIDX[PK], pma_iProductRef[FK], pma_iManufacturerRef[FK], pma_bAvailable)
I have the following POCOs,
public class ProductInfo
{
public int IDX { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductManufacturerInfo> C0ProductManufacturers
{ get; set; }
}
public class ManufacturerInfo
{
public int IDX { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductManufacturerInfo> C0ProductManufacturers
{ get; set; }
}
public class ProductManufacturerInfo
{
public int IDX { get; set; }
public bool Available { get; set; }
public virtual ManufacturerInfo C0Manufacturer { get; set; }
public virtual ProductInfo C0ProductInfo { get; set; }
}
I have used the following mappings without success,
public ProductManufacturerConfiguration()
{
ToTable("ProductManufacturer");
HasKey(p => p.IDX);
Property(p => p.IDX).HasColumnName("pma_iIDX");
Property(p => p.Available).HasColumnName("pma_bAvailable");
Property(p => p.ProductRef).HasColumnName("pma_iProductRef");
Property(p => p.ManufacturerRef).HasColumnName("pma_iManufacturerRef");
//I have tried
HasRequired(p => p.ManufacturerInfo)
.WithMany(c => c.C0ProductManufacturers)
.Map(m => m.MapKey("pma_iManufacturerRef"));
HasRequired(p => p.ProductInfo)
.WithMany(c => c.C0ProductManufacturers)
.Map(m => m.MapKey("pma_iProductRef"));
//As well as
HasRequired(p => p.C0Manufacturer)
.WithMany(c => c.C0ProductManufacturers)
.HasForeignKey(p => p.ManufacturerRef);
HasRequired(p => p.C0Product)
.WithMany(c => c.C0ProductManufacturers)
.HasForeignKey(p => p.C0Product);
}
From my trials, dB first complains about not finding ManufacturerInfo_IDX when I execute the following,
var query = from p in _context.Product
select p;
If I go the code first route, the following table is created,
ProductManufacturer(
pma_iIDX[PK],
pma_iProductRef,
pma_iManufacturerRef,
pma_bAvailable,
ManufacturerInfo_IDX,
ProductInfo_IDX)
Any assistance will be highly appreciated.
I hardly believe that sample you provided is your real code because it even doesn't compile. Is it so hard to copy a real code to show a problem?
This works:
public class ProductInfo
{
public int IDX { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductManufacturerInfo> C0ProductManufacturers
{ get; set; }
}
public class ManufacturerInfo
{
public int IDX { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductManufacturerInfo> C0ProductManufacturers
{ get; set; }
}
public class ProductManufacturerInfo
{
public int IDX { get; set; }
public bool Available { get; set; }
public int ManufacturerRef { get; set; }
public virtual ManufacturerInfo C0Manufacturer { get; set; }
public int ProductRef { get; set; }
public virtual ProductInfo C0ProductInfo { get; set; }
}
public class ProductManufacturerConfiguration : EntityTypeConfiguration<ProductManufacturerInfo>
{
public ProductManufacturerConfiguration()
{
ToTable("ProductManufacturer");
HasKey(p => p.IDX);
Property(p => p.IDX).HasColumnName("pma_iIDX");
Property(p => p.Available).HasColumnName("pma_bAvailable");
Property(p => p.ProductRef).HasColumnName("pma_iProductRef");
Property(p => p.ManufacturerRef).HasColumnName("pma_iManufacturerRef");
//I have tried
HasRequired(p => p.C0Manufacturer)
.WithMany(c => c.C0ProductManufacturers)
.Map(m => m.MapKey("pma_iManufacturerRef"));
HasRequired(p => p.C0ProductInfo)
.WithMany(c => c.C0ProductManufacturers)
.Map(m => m.MapKey("pma_iProductRef"));
//As well as
HasRequired(p => p.C0Manufacturer)
.WithMany(c => c.C0ProductManufacturers)
.HasForeignKey(p => p.ManufacturerRef);
HasRequired(p => p.C0ProductInfo)
.WithMany(c => c.C0ProductManufacturers)
.HasForeignKey(p => p.ProductRef);
}
}
The main problem is that your key for ProductManufacturerInfo should not really be IDX. IDX is more of a "payload" in your many-to-many association. One way to fix this is to specify a true key and then the mapping is easy:
public class ProductManufacturerInfo
{
public int IDX { get; set; }
public bool Available { get; set; }
public int C0ManufacturerIDX { get; set; }
public virtual ManufacturerInfo C0Manufacturer { get; set; }
public int C0ProductInfoIDX { get; set; }
public virtual ProductInfo C0ProductInfo { get; set; }
}
Then your mapping:
public class ProductManufacturerConfiguration
: EntityTypeConfiguration<ProductManufacturerInfo>
{
public ProductManufacturerConfiguration()
{
ToTable("ProductManufacturer");
HasKey(p => new { p.C0ManufacturerIDX, p.C0ProductInfoIDX });
Property(p => p.IDX)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}