[Nhibernate F]loading data to datagridview - c#

I have a problems with retreving data correctly to datagridview. First what i got:
Two classes:
namespace hms.core.Entities
{
public class Osoba : BaseEntity
{
public virtual int Id { get; set; }
public virtual string Imie { get; set; }
public virtual decimal SumaWydatkow { get; set; }
public virtual Dział Dział { get; set; }
}
}
namespace hms.core.Entities
{
public class Dział
{
public virtual int Id { get; set; }
public virtual string Nazwa { get; set; }
public virtual int SumaWydatkowDzialu { get; set; }
public virtual IList<Osoba> Osoby { get; set; }
}
}
And mappings:
namespace hms.data.Mappings
{
public class OsobaMap : ClassMap<Osoba>
{
public OsobaMap()
{
Table("Osoba");
Id(e => e.Id);
Map(e => e.Imie, "Imie").Length(50);
Map(e => e.SumaWydatkow, "SumaWydatkow");
References(e => e.Dział, "IdDzialu").Not.LazyLoad();
}
}
}
namespace hms.data.Mappings
{
public class DziałMapowanie : ClassMap<Dział>
{
public DziałMapowanie()
{
Table("Dział");
Id(e => e.Id);
Map(e => e.Nazwa, "Nazwa").Length(50);
Map(e => e.SumaWydatkowDzialu, "SumaWydatkowDzialu");
HasMany(c => c.Osoby).KeyColumn("IdDzialu").LazyLoad().Cascade.DeleteOrphan().Inverse();
}
}
}
I tried to load data from table Osoba to datagridview, and it's ok, all information are viewing into database but only column "Dział" is showing me in all rows values:
hms.Core.Entities.Dział. How to solve that problem?

I am not familiar with WinForms, but it look like DataGridView does not know how to show your Dział object in columns so it just shows it ToString() representation. I think there should be a way to specify in Dział grid column which property of Dzial to show.

Related

ef core code first generic inheritance mapping

All Positions have a Location (Many-to-1).
Different Location types have different Position types
Model:
public abstract class Location
{
public int Id { get; set; }
public string Name { get; set; }
public int AreaId { get; set; }
public Area Area { get; set; }
public byte[] ConcurrencyToken { get; set; }
}
public abstract class Location<T> : Location where T : Position
{
public ICollection<T> Positions { get; set; } = new List<T>();
}
public class Bay : Location<BayRow> {}
public class StandardLocation : Location<Position> {}
public class Position
{
public int Id { get; set; }
public int? Place { get; set; }
public int LocationId { get; set; }
public Location Location { get; set; }
public byte[] ConcurrencyToken { get; set; }
}
public class BayRow : Position
{
public int? Row { get; set; }
}
The above is abbreviated, there are many more implementations of each. All locations extend the generic class.
Mapping:
modelBuilder.Entity<Position>(entity =>
{
entity.ToTable("Position")
.HasDiscriminator<int>("Type")
.HasValue<Position>(1)
.HasValue<BayRow>(2);
entity.Property(x => x.ConcurrencyToken).IsConcurrencyToken();
//THIS IS THE ISSUE*
entity.HasOne(x => x.Location as Location<Position>).WithMany(x => x.Positions).HasForeignKey(x => x.LocationId);
});
modelBuilder.Entity<Location>(entity =>
{
entity.HasIndex(x => new {x.Name, x.AreaId}).IsUnique(true);
entity.Property(x => x.ConcurrencyToken).IsConcurrencyToken();
entity.HasDiscriminator<int>("Type")
.HasValue<StandardLocation>(1)
.HasValue<Bay<BayRow>>(2)
});
modelBuilder.Entity<Bay<BayRow>>(entity =>
{
entity.HasMany(x => x.Positions).WithOne(x => x.Location as Bay<BayRow>)
.HasForeignKey(x => x.LocationId).OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<BayRow>(entity =>
{
entity.Property(x => x.Row).HasColumnName("Row");
});
*The non-generic Location does not have positions
I've tried adding the collection to the base Location purely for mapping, to avoid ef duplicating/aliasing each location Impl i.e. BayId as LocationId.
publiic ICollection<Position> Positions { get; set; }
and with the new keyword to hide the base collection, but ef projects 2 collections...
public new ICollection<T> Positions { get; set; }
Any insight would be much appreciated.
I'm not sure this is supported by Entity Framework, without generating two tables - one for Bay and one for StandardLocation.
You might try this as a workaround.
public interface ITypedPosition<T> where T: Position
{
IEnumerable<T> Positions { get; }
}
public abstract class Location
{
public int Id { get; set; }
public string Name { get; set; }
public int AreaId { get; set; }
public Area Area { get; set; }
public byte[] ConcurrencyToken { get; set; }
public ICollection<Position> Positions { get; set; }
}
public class Bay : Location, ITypedPosition<BayRow>
{
IEnumerable<BayRow> ITypedPosition<BayRow>.Positions => base.Positions.OfType<BayRow>();
}
public class StandardLocation : Location, ITypedPosition<Position>
{
IEnumerable<Position> ITypedPosition<Position>.Positions => base.Positions.OfType<Position>();
}

How to select the content of different table in one model

What I have:
2 tables, called Content and AboutModel. In Content, I have the following design:
And the AboutModel has the folowing design:
I have these classes in my code:
public class Content : BaseEntity
{
public int Id { get; set; }
public string WebsiteTitle { get; set; }
public string WebsiteDescription { get; set; }
public virtual ICollection<AboutModel> About { get; set; }
}
public class ContentConfiguration : IEntityTypeConfiguration<Content>
{
public void Configure(EntityTypeBuilder<Content> b)
{
b.HasKey(x => x.Id);
}
}
public class AboutModel : BaseEntity
{
public int Id { get; set; }
public string Title { get; set; }
public string Message { get; set; }
public int ContentId { get; set; }
public virtual Content Content { get; set; }
}
public class AboutModelConfiguration : IEntityTypeConfiguration<AboutModel>
{
public void Configure(EntityTypeBuilder<AboutModel> b)
{
b.HasKey(x => x.Id);
}
}
What I had before adding foreign key was this:
var content = _contentRepository.Query().SingleOrDefault();
But when I take the row from the content table, the About collection is null. I need help to understand how to access the about contents.
My goal is to have a file.cshtml and have a model Content and access both Content and About contents from it and display it on the page.
there are few methods to reach that. You can try:
var queryResult = myDbContexy.Content.Include(foo => foo.About).SingleOrDefault();
Or:
var anonymousResult = myDbContext.Content.Select(foo => new {Content = foo, About = foo.About}).ToList();
You can also use Join steatment from LINQ but I don't like it ;)
For more you can read about lazy loading in EF.

Prevent extra column in one to one relationship

I am using Entity-framework code first approach.
Table 1 looks like:
public class CreditUser : BaseEntity
{
public string Id { get; set; }
public string CreditUserName { get; set; }
public string Address { get; set; }
public string Description { get; set; }
public string EmailId { get; set; }
public Accounts Accounts { get; set; }
}
Table 2 looks like:
public class Accounts : BaseEntity
{
public string Id { get; set; }
public decimal TotalAmount { get; set; }
public decimal TotalGivenAmount { get; set; }
public CreditUser CreditUser { get; set; }
}
And fluent api code:
public class AccountsConfiguration : EntityTypeConfiguration<Accounts>
{
public AccountsConfiguration()
{
HasKey(t => t.Id);
HasRequired<CreditUser>(c => c.CreditUser)
.WithOptional(a => a.Accounts)
.WillCascadeOnDelete(false);
}
}
It produces two columns like,
That extra column in the end CreditUser_Id came as automatically. I don't want that. Please help me to solve that issue.
UPDATE
CreditUSer Table Table structure
Solution
As per comments below I tried like in this
public class AccountsConfiguration : EntityTypeConfiguration<Accounts>
{
public AccountsConfiguration()
{
HasRequired<CreditUser>(c => c.CreditUser)
.WithOptional(a => a.Accounts)
.WillCascadeOnDelete(false);
}
}
by removing Key in the fluent Api and it is working.

Entity Framework One-To-Many

First of all I have these two models to store a post in two tables one for shared data and the other contains cultured data for English and Arabic
public class Post
{
public int Id { set; get; }
public bool Active { get; set; }
public bool Featured { get; set; }
public virtual ICollection<PostContent> Contents { get; set; }
}
public class PostContent
{
public int Id { set; get; }
public string Title { get; set; }
public string Summary { get; set; }
public string Details { get; set; }
[StringLength(2)]
public string Culture { get; set; }
public int PostId { get; set; }
[InverseProperty("PostId")]
public virtual Post Post{ set; get; }
}
Mapping
public class PostMap : EntityTypeConfiguration<Post>
{
public PostMap()
{
HasKey(p => p.Id);
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
ToTable("Posts");
}
}
public class PostContentMap : EntityTypeConfiguration<PostContent>
{
public PostContentMap()
{
HasKey(p => p.Id);
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
HasRequired(p => p.Post).WithMany(p => p.Contents).HasForeignKey(p=>p.PostId);
ToTable("PostContents");
}
}
I have two questions
1- Is these models are connected properly. Is there something else I need to do ?
2- I need to select all Posts with their contents where the culture of the content 'en' for example. I used this:
var res = context.Posts.Include(p => p.Contents.Single(c => c.Culture.Equals("en")));
and have this error:
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.Parameter name: path
If you know you are not going to support more than two cultures then I would just add to your Post class.
public class Post
{
public Post()
{
Contents = new List<PostContent>();
}
public int Id { set; get; }
public bool Active { get; set; }
public bool Featured { get; set; }
public int? EnglishContentId { get;set;}
public int? ArabicContentId { get;set;}
PostContent EnglishContent {get;set;}
PostContent ArabicContent {get;set;}
}
public class PostContent
{
public int Id { set; get; }
public string Title { get; set; }
public string Summary { get; set; }
public string Details { get; set; }
[StringLength(2)]
public string Culture { get; set; }/*This property is not required*/
}
public class PostMap : EntityTypeConfiguration<Post>
{
public PostMap()
{
HasKey(p => p.Id);
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
ToTable("Posts");
HasOptional(p => p.EnglishContent).WithMany().HasForeignKey(p=>p.EnglishContentId);
HasOptional(p => p.ArabicContent).WithMany().HasForeignKey(p=>p.ArabicContentId);
}
}
public class PostContentMap : EntityTypeConfiguration<PostContent>
{
public PostContentMap()
{
HasKey(p => p.Id);
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
ToTable("PostContents");
}
}
The Above design will simplify your design and queries, will improve the performance alot.
But if you might have to support more cultures then you got the design and mapping right.
As far as EF 5, include does not allow filters, but I am not sure about EF 6.0
atleast you can get all posts that have english contents as follows
Add using System.Data.Entity;
var res = context.Posts.Include(p => p.Contents).Where(c => c.Contents.Any(cp=>cp.Culture.Equals("en")));

EF4 Code only mapping inheritance

I've got the following model and I want ShiftRequest and MissionRequest to have a single table in the DB.
public class RequestBase
{
public int Id { get; set; }
public DateTime? RequestDate { get; set; }
public int UserId { get; set; }
public virtual ICollection<Notification> Notifications { get; set; }
}
public class ShiftRequest : RequestBase
{
public virtual Column Column { get; set; }
}
public class MissionRequest : RequestBase
{
public virtual Mission Mission { get; set; }
}
I've tried to do it in the override void OnModelCreating(ModelBuilder modelBuilder) method but only one RequestBases table is created:
modelBuilder.Entity<ShiftRequest>().MapSingleType().ToTable("dbo.ShiftRequests");
modelBuilder.Entity<MissionRequest>().MapSingleType().ToTable("dbo.MissionRequest");
What am I doing wrong?
EDIT
Column and Mission are also entities in my model, is that acceptable?
Check the section about TPH in this article. If Mission and Column are complex types you will also find there how to map them. Generally you have to use MapHiearchy and Case methods instead of MapSingleType.
Edit:
Here is the example:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
namespace EFTest
{
public class RequestBase
{
public int Id { get; set; }
public DateTime? RequestedDate { get; set; }
public int UserId { get; set; }
}
public class Mission
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<MissionRequest> MissionRequests { get; set; }
}
public class Column
{
public string Name { get; set; }
}
public class MissionRequest : RequestBase
{
public virtual Mission Mission { get; set; }
}
public class ShiftRequest : RequestBase
{
public Column Column { get; set; }
}
public class TestContext : DbContext
{
public DbSet<RequestBase> Requests { get; set; }
public DbSet<Mission> Missions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ContainerName = "EFTest";
modelBuilder.IncludeMetadataInDatabase = false;
// Example of complex type mapping. First you have to define
// complex type. Than you can access type properties in
// MapHiearchy.
var columnType = modelBuilder.ComplexType<Column>();
columnType.Property(c => c.Name).HasMaxLength(50);
modelBuilder.Entity<Mission>()
.Property(m => m.Id)
.IsIdentity();
modelBuilder.Entity<Mission>()
.HasKey(m => m.Id)
.MapSingleType(m => new { m.Id, m.Name })
.ToTable("dbo.Missions");
modelBuilder.Entity<RequestBase>()
.Property(r => r.Id)
.IsIdentity();
// You map multiple entities to single table. You have to
// add some discriminator to differ entity type in the table.
modelBuilder.Entity<RequestBase>()
.HasKey(r => r.Id)
.MapHierarchy()
.Case<RequestBase>(r => new { r.Id, r.RequestedDate, r.UserId, Discriminator = 0 })
.Case<MissionRequest>(m => new { MissionId = m.Mission.Id, Discriminator = 1 })
.Case<ShiftRequest>(s => new { ColumnName = s.Column.Name, Discriminator = 2 })
.ToTable("dbo.Requests");
}
}
}
Edit 2:
I updated example. Now Mission is entity instead of complex type.

Categories

Resources