Entity FrameWork lazy loading 0 to many fluent api mapping issue - mysql

I been breaking my head for hours trying to find out why my navigation property is coming back null for 0 to many scenario. For 1 to 1 it works just fine.
These are my entities:
public class Barber: BaseEntity
{
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public int? AppointmentId { get; set; }
public int? UserId { get; set; }
public virtual ICollection<Users> Users { get; set; }
public Barber()
{
}
}
public class Users: BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public bool IsBarber { get; set; }
public int? BarberId { get; set; }
public string FacebookToken { get; set; }
public DateTime? CreatedOn { get; set;}
public virtual Barber Barber { get; set; }
/// <summary>
/// default constructor
/// </summary>
public Users() { }
}
my mapping is as follow:
for Barber:
public BarberMapping()
{
ToTable("Barber");
HasKey(p => p.Id);
Property(p => p.Street1).HasColumnName("Street1");
Property(p => p.Street2).HasColumnName("Street2");
Property(p => p.City).HasColumnName("City");
Property(p => p.State).HasColumnName("State");
Property(p => p.PostalCode).HasColumnName("PostalCode");
Property(p => p.AppointmentId).HasColumnName("AppointmentId");
Property(p => p.UserId).HasColumnName("UserId");
HasOptional(p => p.Users)
.WithMany()
.HasForeignKey(p => p.UserId);
}
}
for User:
public UserMapping()
{
ToTable("Users");
HasKey(p => p.Id);
Property(p => p.FirstName);
Property(p => p.LastName );
Property(p => p.Password);
Property(p => p.Email);
Property(p => p.CreatedOn);
Property(p => p.FacebookToken);
Property(p => p.IsBarber);
}
Finally i'm calling my data like this:
_userRepository.All.Where(p => p.Id == id).Include(p => p.Barber).FirstOrDefault();
When the query comes back I get everything except the Barber property which comes back as null. Anything i'm missing to make this relationShip work?
I'm using EF 6.1.3 with mySQL 6.9 on visual studio for mac.

Related

I want to Add a foreignkey for a table using onModelCreating method in asp.net core

I created two tables named 'patient' and 'Admission'.For do that i created patient model and admission model classes.then i use HospitalDbContext class for creating tables using onModelCreating method. I want to use PatientId as a foreign-key of Admission table.But i can't find a way to add foreign key.Help me to solve this problem
Patient.cs :
public class Patient
{
public int PatientId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Nic { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public DateTime RegisterDate { get; set; }
public string CurrentState { get; set; }
public string Password { get; set; }
}
Admission.cs :
public class Admission
{
public int AdmissionId { get; set; }
public int PatientId { get; set; }
public DateTime AdmissionDate { get; set; }
public string reason { get; set; }
}
HospitalDbContext.cs :
public class HospitalDbContext : DbContext
{
public HospitalDbContext(DbContextOptions<HospitalDbContext> options)
: base(options)
{
}
public DbSet<Patient> Patients { get; set; }
public DbSet<Admission> Admissions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Patient>(entity =>
{
entity.HasKey(e => e.PatientId);
entity.Property(e => e.FirstName);
entity.Property(e => e.LastName);
entity.Property(e => e.Nic);
entity.Property(e => e.Age);
entity.Property(e => e.Address);
entity.Property(e => e.Email);
entity.Property(e => e.Mobile);
entity.Property(e => e.RegisterDate);
entity.Property(e => e.CurrentState);
entity.Property(e => e.Password);
});
modelBuilder.Entity<Admission>(entity=>
{
entity.HasKey(e => e.AdmissionId);
entity.Property(e => e.PatientId);
entity.Property(e => e.AdmissionDate);
entity.Property(e => e.reason);
});
}
public DbSet<patient_information_system_api.Models.Admission> Admission { get; set; }
}
As far as I know, we couldn't directly create the relationship without modifying the your Patient and Admission class.
If you want to achieve one to one relationship between the Admission and Patient, you should add Admission and Patient as property in each class and then use entity.HasOne(x=>x.Patient).WithOne(x=>x.Admission).HasForeignKey("PatientId"); to achieve your requirement.
More details, you could refer to below codes:
public class Patient
{
public int PatientId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Nic { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public DateTime RegisterDate { get; set; }
public string CurrentState { get; set; }
public string Password { get; set; }
public Admission Admission { get; set; }
}
Admission:
public class Admission
{
public int AdmissionId { get; set; }
public int PatientId { get; set; }
public DateTime AdmissionDate { get; set; }
public string reason { get; set; }
public Patient Patient{ get; set; }
}
OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Patient>(entity =>
{
entity.HasKey(e => e.PatientId);
entity.Property(e => e.FirstName);
entity.Property(e => e.LastName);
entity.Property(e => e.Nic);
entity.Property(e => e.Age);
entity.Property(e => e.Address);
entity.Property(e => e.Email);
entity.Property(e => e.Mobile);
entity.Property(e => e.RegisterDate);
entity.Property(e => e.CurrentState);
entity.Property(e => e.Password);
});
modelBuilder.Entity<Admission>(entity =>
{
entity.HasKey(e => e.AdmissionId);
entity.Property(e => e.PatientId);
entity.Property(e => e.AdmissionDate);
entity.Property(e => e.reason);
entity.HasOne(x=>x.Patient).WithOne(x=>x.Admission).HasForeignKey("PatientId");
});
}
You don't need to create foreign key there, just go to the Model that
you need to add foreign key on it and make a virtual from from the
model class that you need:
In your case, you can apply it like this:
public class Admission
{
public int AdmissionId { get; set; }
public int PatientId { get; set; }
[ScaffoldColumn(false)] //Add this to avoid create foreign key when scaffolding
public virtual Patient Patient {get; set;} //Add this to work as foreign key
public DateTime AdmissionDate { get; set; }
public string reason { get; set; }
}
After that when you need to read the foreign key, you can read it easily as follow:
//.Include used to read the foreign key
var _admission = await db.admission.Include(a => a.Patient).OrderBy(x => x.AdmissionDate);
And you can read more about foreign key and relationships from this link:
https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key

Automapper Projection with Linq OrderBy child property error

I am having an issue using an AutoMapper (version 5.1.1) projection combined with a Linq OrderBy Child property expression. I am using Entity Framework Core (version 1.0.0). I am getting the following error:
"must be reducible node"
My DTO objects are as follows
public class OrganizationViewModel
{
public virtual int Id { get; set; }
[Display(Name = "Organization Name")]
public virtual string Name { get; set; }
public virtual bool Active { get; set; }
public virtual int OrganizationGroupId { get; set; }
public virtual string OrganizationGroupName { get; set; }
public virtual int StrategyId { get; set; }
public virtual string StrategyName { get; set; }
public virtual OrganizationGroupViewModel OrganizationGroup { get; set; }
}
public class OrganizationGroupViewModel
{
public virtual int Id { get; set; }
[Display(Name = "Organization Group Name")]
public virtual string Name { get; set; }
public virtual bool Active { get; set; }
}
My corresponding entity models are as follows:
public class Organization
{
public int Id { get; set; }
public string Name { get; set; }
public string TimeZone { get; set; }
public bool Active { get; set; }
//FKs
public int OrganizationGroupId { get; set; }
public int StrategyId { get; set; }
//Navigation
public virtual OrganizationGroup OrganizationGroup { get; set; }
public virtual Strategy Strategy { get; set; }
[JsonIgnore]
public virtual List<AppointmentReminder> AppointmentReminders { get; set; }
}
public class OrganizationGroup
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public virtual List<Organization> Organizations { get; set; }
}
My AutoMapper profiles are as follows:
public class OrganizationMapperProfile : Profile
{
public OrganizationMapperProfile()
{
CreateMap<Task<Organization>, Task<OrganizationViewModel>>();
CreateMap<Organization, OrganizationViewModel>()
.ForMember(dest => dest.OrganizationGroupName, opt => opt.MapFrom(src => src.OrganizationGroup.Name));
CreateMap<OrganizationInput, Organization>()
.ForMember(x => x.Id, opt => opt.Ignore());
}
}
public class OrganizationGroupMapperProfile : Profile
{
public OrganizationGroupMapperProfile()
{
CreateMap<Task<OrganizationGroup>, Task<OrganizationGroupViewModel>>();
CreateMap<OrganizationGroup, OrganizationGroupViewModel>();
CreateMap<OrganizationGroupInput, OrganizationGroup>()
.ForMember(x => x.Id, opt => opt.Ignore());
}
}
When I run the following statements I am able to run and get results from the first 2 statements:
var tmp = await _context.Organizations.Include(x => x.OrganizationGroup).OrderBy(x => x.OrganizationGroup.Name).ToListAsync();
var tmp4 = await _context.Organizations.Include(x => x.OrganizationGroup).OrderBy("OrganizationGroup.Name").ToListAsync();
But when I add the ProjectTo I get the error listed above:
var tmp5 = await _context.Organizations.Include(x => x.OrganizationGroup).OrderBy(x => x.OrganizationGroup.Name).ProjectTo<OrganizationViewModel>().ToListAsync();
var tmp6 = await _context.Organizations.Include(x => x.OrganizationGroup).OrderBy("OrganizationGroup.Name").ProjectTo<OrganizationViewModel>().ToListAsync();
As some additional information, I am able to OrderBy with Projections working on properties of the parent class, such as:
var tmp7 = await _context.Organizations.Include(x => x.OrganizationGroup).OrderBy(x => x.Name).ProjectTo<OrganizationViewModel>().ToListAsync();
var tmp8 = await _context.Organizations.Include(x => x.OrganizationGroup).OrderBy("Name").ProjectTo<OrganizationViewModel>().ToListAsync();
Anyone run into this issue before? Looks like I'm trying to do something that is otherwise not supported, is that by design? Thanks for any help/insight.
Looks like the problem is caused by the OrganizationGroup property of the OrganizationViewModel class - AutoMapper generates a null check which EF Core doesn't like in the combination with your OrderBy (I guess just one of the many bugs currently in EF Core). It can easily be reproduced by the following simple manual projection query:
var tmp5a = _context.Organizations
.OrderBy(x => x.OrganizationGroup.Name)
.Select(e => new OrganizationViewModel
{
Id = e.Id,
OrganizationGroup = e.OrganizationGroup != null ? new OrganizationGroupViewModel
{
Id = e.OrganizationGroup.Id,
Name = e.OrganizationGroup.Name,
Active = e.OrganizationGroup.Active,
} : null,
})
.ToList();
To fix the issue, configure AutoMapper to not generate null check for that property as follows:
CreateMap<Organization, OrganizationViewModel>()
.ForMember(dest => dest.OrganizationGroup, opt => opt.AllowNull())
.ForMember(dest => dest.OrganizationGroupName, opt => opt.MapFrom(src => src.OrganizationGroup.Name));

Entity Framewrok 5 fluent mapping for many to many with 3 entities

I have the following scenario that is giving me a hard time:
public class SegUser
{
public string IdUser { get; set; }
public List<SegRol> SegRoles { get; set; }
public virtual List<SegApps> Apps{ get; set; }
}
public class SegRole
{
public virtual int IdRole { get; set; }
public virtual List<SegUer> SegUsers { get; set; }
public virtual List<SegApp> Apps { get; set; }
}
public class SegApp
{
public virtual int IdApp{ get; set; }
public virtual List<SegUser> Users { get; set; }
public virtual List<SegRole> Roles { get; set; }
}
In my database I have those 3 tables and an extra table with 3 PKs (one for each entity) to establish the relationship between those 3 entities.
How can I achieve the mapping with Entity Framework 5 fluent API.
I've already tried:
private void MapSegUser()
{
//mapping of another fields
entityConfiguration
.HasMany(x => x.SegRoles)
.WithMany(x => x.SegUsers)
.Map(mc =>
{
mc.MapLeftKey("id_role");
mc.MapRightKey("id_user");
mc.ToTable("seg_users_roles");
});
entityConfiguration
.HasMany(x => x.Apps)
.WithMany(x => x.Users)
.Map(mc =>
{
mc.MapLeftKey("id_app");
mc.MapRightKey("id_user");
mc.ToTable("seg_users_roles_apps");
});
}
private void MapSegApp()
{
//mapping of another fields
entityConfiguration
.HasMany(x => x.Users)
.WithMany(x => x.Apps)
.Map(mc =>
{
mc.MapLeftKey("id_user");
mc.MapRightKey("id_app");
mc.ToTable("seg_users_roles_apps");
});
}
private void MapSegRole()
{
//mapping of another fields
entityConfiguration
.HasMany(x => x.SegUsers)
.WithMany(x => x.SegRoles)
.Map(mc =>
{
mc.MapLeftKey("id_user");
mc.MapRightKey("id_role");
mc.ToTable("seg_users_roles");
});
}

How do I get around this cyclical reference in EF?

I am using Entity Framework Code First with SQLCE in MVC3 for a blog-like site.
I am open to redesigning the structure if required, it would be great to get some help.
The context is set up as:
public class BinarContext : DbContext
{
public DbSet<Member> Members { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Reply> Replies { get; set; }
public BinarContext()
{
this.Configuration.LazyLoadingEnabled = true;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Member>().HasMany(member => member.Posts)
.WithRequired(post => post.Member)
.HasForeignKey(post => post.MemberID)
.WillCascadeOnDelete();
modelBuilder.Entity<Member>().HasMany(member => member.Replies)
.WithRequired(reply => reply.Member)
.HasForeignKey(reply => reply.MemberID)
.WillCascadeOnDelete();
modelBuilder.Entity<Post>().HasMany(post => post.Replies)
.WithRequired(reply => reply.Post)
.HasForeignKey(reply => reply.PostID)
.WillCascadeOnDelete();
base.OnModelCreating(modelBuilder);
}
}
*Note: * I have tried getting rid of WillCascadeOnDelete(); as suggested by others on SO but hasn't worked so far.
The models are:
The Member class has information about the posts and replies made by the member.
public class Member
{
public Guid ID {get; set;}
public string Username { get; set; }
public string Email { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public virtual ICollection<Reply> Replies { get; set; }
}
The Post class that has information about the member who posted it and for the replied posted for it.
public class Post
{
public Guid ID {get; set;}
[DataType(DataType.MultilineText)]
public string Text { get; set; }
public Guid MemberID { get; set; }
public virtual Member Member { get; set; }
public virtual ICollection<Reply> Replies { get; set; }
}
The Reply class that has information about the member who posted it and for the post it was posted.
public class Reply
{
public Guid ID { get; set; }
[DataType(DataType.MultilineText)]
public string Text { get; set; }
public Guid PostID { get; set; }
public Guid MemberID { get; set; }
public virtual Post Post { get; set; }
public virtual Member Member { get; set; }
}
Thanks for your help :)
Try this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Member>().HasKey(x=>x.ID)
.HasMany(x => x.Posts)
.WillCascadeOnDelete();
modelBuilder.Entity<Member>().HasKey(x=>x.ID)
.HasMany(x => x.Replies)
.WillCascadeOnDelete();
modelBuilder.Entity<Post>().HasKey(x=>x.ID)
.HasMany(x => x.Replies)
.WillCascadeOnDelete();
modelBuilder.Entity<Post>().HasKey(x=>x.ID)
.WithRequired(x => x.Member)
.WithMany(x=>x.Posts);
modelBuilder.Entity<Replies>().HasKey(x=>x.ID)
.WithRequired(x => x.Member)
.WithMany(x=>x.Replies);
modelBuilder.Entity<Replies>().HasKey(x=>x.ID)
.WithRequired(x => x.Post)
.WithMany(x=>x.Replies);
base.OnModelCreating(modelBuilder);
}

NHibernate and MySql is inserting and Selecting, not updating

Something strange is going on with NHibernate for me. I can select, and I can insert. But I can't do and update against MySql.
Here is my domain class
public class UserAccount
{
public virtual int Id { get; set; }
public virtual string UserName { get; set; }
public virtual string Password { get; set; }
public virtual bool Enabled { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string Phone { get; set; }
public virtual DateTime? DeletedDate { get; set; }
public virtual UserAccount DeletedBy { get; set; }
}
Fluent Mapping
public class UserAccountMap : ClassMap<UserAccount>
{
public UserAccountMap()
{
Table("UserAccount");
Id(x => x.Id);
Map(x => x.UserName);
Map(x => x.Password);
Map(x => x.FirstName);
Map(x => x.LastName);
Map(x => x.Phone);
Map(x => x.DeletedDate);
Map(x => x.Enabled);
}
}
Here is how I'm creating my Session Factory
var dbconfig = MySQLConfiguration
.Standard
.ShowSql()
.ConnectionString(a => a.FromAppSetting("MySqlConnStr"));
FluentConfiguration config = Fluently.Configure()
.Database(dbconfig)
.Mappings(m =>
{
var mapping = m.FluentMappings.AddFromAssemblyOf<TransactionDetail>();
mapping.ExportTo(mappingdir);
});
and this is my NHibernate code:
using (var trans = Session.BeginTransaction())
{
var user = GetById(userId);
user.Enabled = false;
user.DeletedDate = DateTime.Now;
user.UserName = "deleted_" + user.UserName;
user.Password = "--removed--";
Session.Update(user);
trans.Commit();
}
No exceptions are being thrown. No queries are being logged. Nothing.
Do you have auto flushing configured? You're calling a commit for transactions on your session but no flush on the session.