Prevent extra column in one to one relationship - c#

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.

Related

EF include list is always null

By some reason EF wont load the included list properly so it ends up being null all the time.
Here is the entities i'm using:
[Table("searchprofilepush")]
public class SearchProfilePush
{
public int Id { get; set; }
public int AccountId { get; set; }
public bool Push { get; set; }
public int UserPushId { get; set; }
public UserPush UserPush { get; set; }
public int SearchProfileId { get; set; }
public SearchProfile SearchProfile { get; set; }
public ICollection<SearchProfileMediaTypePush> SearchProfileMediaTypePush { get; set; }
}
[Table("searchprofilemediatypepush")]
public class SearchProfileMediaTypePush
{
public int Id { get; set; }
public MediaTypeType MediaType { get; set; }
public bool Push { get; set; }
public int SearchProfilePushId { get; set; }
public SearchProfilePush SearchProfilePush { get; set; }
}
Then when i'm trying to do this:
var searchProfilePush = _dataContext.SearchProfilePush.Include(w => w.SearchProfileMediaTypePush).FirstOrDefault(w => w.AccountId == accountId && w.SearchProfileId == searchProfileId);
My included list is always null.
I guess it's some obvious reason why this doesn't work but i just can't figure it out.
Thanks!
EDIT:
Here is the sql query:
SELECT \"Extent1\".\"id\", \"Extent1\".\"accountid\", \"Extent1\".\"push\", \"Extent1\".\"userpushid\", \"Extent1\".\"searchprofileid\" FROM \"public\".\"searchprofilepush\" AS \"Extent1\" WHERE \"Extent1\".\"accountid\" = #p__linq__0 AND #p__linq__0 IS NOT NULL AND (\"Extent1\".\"searchprofileid\" = #p__linq__1 AND #p__linq__1 IS NOT NULL) LIMIT 1
EDIT 2:
I have now mapped my entities both way and the list is still always null.
Edit 3:
This is how i created my database tables.
The documentation I read for loading related entities has some differences with the sample code and your code. https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx
First, when you define your ICollection, there is no keyword virtual:
public virtual ICollection<SearchProfileMediaTypePush> SearchProfileMediaTypePush { get; set; }
Next, in the example close to yours, where they load related items using a query, the first or default is not using a boolean expression. The selective expression is in a where clause:
// Load one blogs and its related posts
var blog1 = context.Blogs
.Where(b => b.Name == "ADO.NET Blog")
.Include(b => b.Posts)
.FirstOrDefault();
So you can try:
var searchProfilePush = _dataContext.SearchProfilePush
.Where(w => w.AccountId == accountId && w.SearchProfileId == searchProfileId)
.Include(w => w.SearchProfileMediaTypePush)
.FirstOrDefault();
Can you make these two changes and try again?
A few things will be an issue here. You have no keys defined or FKs for the relationship:
[Table("searchprofilepush")]
public class SearchProfilePush
{
[Key]
public int Id { get; set; }
public int AccountId { get; set; }
public bool Push { get; set; }
public int UserPushId { get; set; }
public UserPush UserPush { get; set; }
public int SearchProfileId { get; set; }
public SearchProfile SearchProfile { get; set; }
public ICollection<SearchProfileMediaTypePush> SearchProfileMediaTypePush { get; set; }
}
[Table("searchprofilemediatypepush")]
public class SearchProfileMediaTypePush
{
[Key]
public int Id { get; set; }
public MediaTypeType MediaType { get; set; }
public bool Push { get; set; }
public int SearchProfilePushId { get; set; }
[ForeignKey("SearchProfilePushId")]
public SearchProfilePush SearchProfilePush { get; set; }
}
Personally I prefer to explicitly map out the relationships using EntityTypeConfiguration classes, but alternatively they can be set up in the Context's OnModelCreating. As a starting point have a look at http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx for basic EF relationship configuration.
for a SearchProfilePush configuration:
modelBuilder.Entity<SearchProfilePush>()
.HasMany(x => x.SearchProfileMediaTypePush)
.WithRequired(x => x.SearchProfilePush)
.HasForeignKey(x => x.SearchProfilePushId);

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.

How to seed this entity model framework for complex relationship

I have the following scenario. We need to be able to fill forms for some tables, examples Companies (Empresa in Spanish), however we want the administrator to be able to extend the entity itself with additional fields.
I designed the following classes, and I need to seed at least one row, however its unclear to me how to seed one row of type CampoAdicional
Entity class:
public abstract class Entidad
{
[Key]
public int Id { get; set; }
}
Company Class (Empresas)
public class Empresa : Entidad
{
public string Nombre { get; set; }
public string NIT { get; set; }
public string NombreRepresentanteLegal { get; set; }
public string TelefonoRepresentanteLegal { get; set; }
public string NombreContacto { get; set; }
public string TelefonoContacto { get; set; }
public virtual ICollection<CampoAdicional> CamposAdicionales { get; set; }
}
And the Additional Fields (Campo Adicional)
public class CampoAdicional
{
[Key]
public int Id { get; set; }
public string NombreCampo { get; set; }
public virtual Tiposcampo TipoCampo { get; set; }
public virtual Entidad Entidad { get; set; }
}
However I dont know how to seed this class or table, because entity should be of subtype Company
Obviously the typeof doesnt compile
context.CampoAdicionals.Add(new CampoAdicional() { Entidad = typeof(Empresa), Id = 1, NombreCampo = "TwitterHandle", TipoCampo = Tiposcampo.TextoUnaLinea });
Update 1: Please note that the additional fields are for the entire entity company not for each company.
Unfortunately, I don't think you'll be able to use EF to automatically create that kind of relationship. You might be able to do something similar with special getters and such:
public class Entidad
{
// stuff...
public IEnumerable<CampoAdicional> CamposAdicionales
{
get { return CampoAdicional.GetAll(this); }
}
}
public class CampoAdicional
{
[Key]
public int Id { get; set; }
public string NombreCampo { get; set; }
public virtual Tiposcampo TipoCampo { get; set; }
protected string EntidadType { get; set; }
// You will need some mapping between Type and the EntidadType string
// that will be stored in the database.
// Maybe Type.FullName and Type.GetType(string)?
protected Type MapEntidadTypeToType();
protected string MapTypeToEntidadType(Type t);
[NotMapped]
public Type
{
get { return MapEntidadTypeToType(); }
// maybe also check that Entidad.IsAssignableFrom(value) == true
set { EntidadType = MapTypeToEntidadType(value); }
}
public static IEnumerable<CampoAdicional> GetAll(Entidad ent)
{
return context.CampoAdicionals
.Where(a => a.EntidadType == MapTypeToEntidadType(ent.GetType()));
}
}

[Nhibernate F]loading data to datagridview

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.

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