In entity framework core, how we can set relationship for a table, when two fields is mapping to primary key of the another table - sql

In entity framework core, how we can set relationship for a table, when two fields is mapping to primary key of the another table.
For example I have two table namely Users & CashBox.
Users Table
Field
Value
UserId
int
UserName
string
CashBox Table
Field
Value
CashBoxId
int
ActivatedBy
int
DeactivatedBy
int
In this case, activatedby & deactivatedby has to be linked with user table. Need to know who activated cashbox & who deactivated cashbox.
Using EF core code first approach.

With the following entity models -
public class User
{
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
}
public class CashBox
{
[Key]
public int CashBoxId { get; set; }
public int ActivatedBy { get; set; }
public int DeactivatedBy { get; set; }
public User ActivatedUser { get; set; }
public User DeactivatedUser { get; set; }
}
you can configure the relationship as -
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CashBox>(e =>
{
e.HasOne(p => p.ActivatedUser)
.WithMany()
.HasForeignKey(p => p.ActivatedBy);
e.HasOne(p => p.DeactivatedUser)
.WithMany()
.HasForeignKey(p => p.DeactivatedBy);
});
}

Related

How to set up relationship using entity framework core

I have Two Model
public class User: Entity
{
public string Gender { get; set; }
public string Name { get; set; }
}
And
public class CognitoUser : Entity
{
public string UserId { get; set; }
public User User{ get; set; }
public string CognitoName { get; set; }
}
I want to set Cognito.UserId as User.Id . I have written the following which is not working can you please correct me as i dont want to create a model CognitoUser into user model.
modelBuilder.Entity<CognitoUser>(e =>
{
e.ToTable("CognitoUser");
e.HasKey(p => p.UserId);
e.HasOne(x => x.User)
.HasForeignKey<User>(c => c.Id);
});
Primary keys are required in each Entity which is missing in your User Entity.
Using Fluent API is optional. If you set your classes right, Entity Framework will understand what you want to achieve.
Hints:
Use [Key] attribute to specify a property as primary key
Prefered primary key format would be {ClassName}{Id}
Use [DatabaseGenerated(DatabaseGeneratedOption.Identity)] to force database
to automatically generate primary key for you.
You can use Guid as primary key type, it is always unique and hassle-free
Additionally, check out the code below to see how to create a relation.
public class User: Entity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UserId { get; set; }
public string Gender { get; set; }
public string Name { get; set; }
}
public class CognitoUser: Entity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid CognitoUserId { get; set; }
public string CognitoName { get; set; }
// relation
public Guid UserId { get; set; }
public User User { get; set; }
}
Visualization:

Link two tables with a one-to-one relationship, using the same unique key

I have two tables that need to be linked one to one by the key field email.
When I try to do this, I get an error like this:
Cannot use table 'UserSettings' for entity type 'UserSettings' since it is being used for entity type 'UserSettings' and potentially other entity types, but there is no linking relationship. Add a foreign key to 'UserSettings' on the primary key properties and pointing to the primary key on another entity type mapped to 'UserSettings'.
how I tried to implement it:
public class UserSettingsConfiguration : IEntityTypeConfiguration<UserSettings>
{
public void Configure(EntityTypeBuilder<UserSettings> builder)
{
builder.HasKey(n => n.Email);
builder.HasOne(n => n.User)
.WithOne(u => u.UserSettings)
.HasForeignKey<UserSettings>(k => k.Email)
.HasPrincipalKey<UserSettings>(k => k.Email);
}
}
UserSettings and User entities:
public class User
{
public string Email { get; set; }
public DateTime RegistrationDate { get; set; }
public string Image { get; set; }
public UserSettings UserSettings { get; set; }
}
public class UserSettings
{
public string Email { get; set; }
public int LanguageId { get; set; }
public User User { get; set; }
}

How can I make a foreign key relationship between an identity server column and another custom table?

I use identity server.
I know that if I want to add new columns, I make a new class which will inherit from IdentityUser, and in SQL Server with EF, the column will be generated. But I want to have a "Gender" column which will have a foreign key relationship with another custom-made table: "1" will be for "male", "2" for "female" etc.
I also want to make a similar relationship with another table where the programming languages of every employee will be stored.
Is that possible?
public ApplicationUser : IdentityUser
{
public string FullName {get ; set; }
public int GenderId { get ; set ;}
public ICollection<ProgrammingLanguages> PL {get ; set ;}
}
Basically you need to implement one-to-many relationship between User and Gender tables and many-to-many relationship between User and ProgrammingLanguage. Many-to-many relationship requires extra table which will contain foreign keys to User and ProgrammingLanguage tables. You then need to override OnModelCreating() method and don't forget to call the base implementation of OnModelCreating() method so that let the base implementation to setup relationships between identity tables. You can read more on how to implement relationships between entities here. Here is the sample code how this can be done:
public ApplicationUser : IdentityUser
{
public string FullName { get; set; }
public int GenderId { get; set; }
public Gender Gender { get; set; }
public ICollection<UserProgrammingLanguage> UserProgrammingLanguages { get; set;}
}
public class ProgrammingLanguage
{
public int Id { get; set; }
public string Name { get; set; }
}
public class UserProgrammingLanguage
{
public string UserId { get; set; }
public ApplicationUser User { get; set; }
public int ProgrammingLanguageId { get; set; }
public ProgrammingLanguage ProgrammingLanguage { get; set; }
}
public class Gender
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ApplicationContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Gender> Genders { get; set; }
public DbSet<ProgrammingLanguage> ProgrammingLanguages { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<UserProgrammingLanguage>(entity =>
{
entity.HasKey(pl => { pl.UserId, pl.ProgrammingLanguageId });
entity.HasOne(pl => pl.User)
.WithMany(u => u.UserProgrammingLanguages)
.HasForeignKey(pl => pl.UserId);
entity.HasOne(pl => pl.ProgrammingLanguage)
.WithMany()
.HasForeignKey(pl => pl.ProgrammingLanguageId);
}
builder.Entity<ApplicationUser>(entity =>
{
entity.HasOne(u => u.Gender)
.WithMany()
.HasForeignKey(u => u.GenderId)
.OnDelete(DeleteBehavior.Cascade);
})
base.OnModelCreating(builder);
}
}

How to Insert data in table when Foreign Key is not a primary key

I created a Model with Entity Framework Code First and have two classes
Product.cs
public class Product
{
public Product()
{
Certificates = new HashSet<Certificate>();
}
public int ProductId { get; set; }
public int ProductCode { get; set; }
public decimal Price { get; set; }
public string Type { get; set; }
public string SubType { get; set; }
public int RelatedProductId { get; set; }
public string Description { get; set; }
public string DescriptionSpanish { get; set; }
public string ShortDescription { get; set; }
public string CertificateDescription { get; set; }
public string QBItemCode { get; set; }
public string QBDescCode { get; set; }
public virtual ICollection<Certificate> Certificates { get; set; }
}
Certificate.cs
public class Certificate
{
public int CertificateId { get; set; }
public string Type { get; set; }
public string Course { get; set; }
public DateTime DateGranted { get; set; }
public string NameOnCertificate { get; set; }
public int FinalExamQuestionsCorrect { get; set; }
public int FinalExamQuestionsTotal { get; set; }
public string ClientIPAddress { get; set; }
public int ProductCode { get; set; }
public virtual Product Product { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
ProductConfiguration.cs
public class ProductConfiguration : EntityTypeConfiguration<Product>
{
public ProductConfiguration()
{
HasKey(p => p.ProductId);
Property(p => p.ProductId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(p => p.ProductCode)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("AK_Product_ProductCode") { IsUnique = true }));
}
}
CertificateConfiguration.cs
public class CertificateConfiguration : EntityTypeConfiguration<Certificate>
{
public CertificateConfiguration()
{
HasKey(c => c.CertificateId);
Property(c => c.CertificateId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(p => p.ProductCode).HasColumnName("ProductId");
HasRequired(c => c.ApplicationUser)
.WithMany(u => u.Certificates)
.HasForeignKey(c => c.UserId);
HasRequired(c => c.Product)
.WithMany(p => p.Certificates)
.HasForeignKey(c => c.ProductCode);
}
}
Notice, I created a Foreign Key ProductCode (rename it to ProductId) in Certificate Table.
I also seeded Product table with some data in which the ProductId generated by database and ProductCode that I manually defined. The problem is when I am trying to insert a record in Certificate table by running a sql query in which I defined a foreign key that's actually a ProductCode (not ProductId), it throws an error
SQL QUERY:
Insert into [dbo].[Certificates]
values (
'TestType','TestCourse',GETUTCDATE(),'TestName',1,5,
'127.0.0.1',201,'userId'
)
201 is the ProductCode in query that exist in Product table
Error
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Certificates_dbo.Products_ProductId". The conflict occurred in database "myDatabse", table "dbo.Products", column 'ProductId'.
I am not sure why it's looking for Primary Key ProductId. It should look for the ProductCode in Product table weather it exist or not.
I believe you're running into a limitation of EF whereby your FK on the dependent end of the relationship has to refer back to the PK on the principal end. When you configure the relationship between Product and Certificates here:
HasRequired(c => c.Product)
.WithMany(p => p.Certificates)
.HasForeignKey(c => c.ProductCode);
this establishes the foreign key relationship between the Product primary key - Product.ProductId - and the foreign key you defined - Certificate.ProductCode (named Certificate.ProductId in your table).
While the database will support FK referring back to a unique key in your table, EF does not support it (at this time).
Here are a few other SO questions that cover this issue:
How to get EF6 to honor Unique Constraint (on FK) in Association/Relationship multiplicity?
Database first Entity Framework mapping unique foreign keys as one to many
And here's the official feature request to add this feature to EF:
Unique Constraint (i.e. Candidate Key) Support
According to the comments, it looks like they are working adding this in EF7.

How to use composite Ids in one-to-many mappings in fluent nhibernate?

I got a scenario where a composite Id uniquely identifies an entity. I defined the MSSQL to have a multiple primary key on those fields. In addition I would like an auto-incremented id to be used for referencing a one-to-many relationship. Here's the schema:
public class Character
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Region Region { get; set; }
public virtual string Realm { get; set; }
public virtual IList<CharProgression> Progression { get; set; }
}
public class CharProgression
{
public virtual int Id { get; set; }
public virtual Character Character { get; set; }
public virtual Stage Stage { get; set; }
public virtual int ProgressionPoints { get; set; }
public virtual int NumOfSaves { get; set; }
}
public class Stage
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
}
The mappings look like this:
class CharacterMap : ClassMap<Character>
{
public CharacterMap()
{
Table("characters");
Id(ch => ch.Id, "id").GeneratedBy.Identity().Not.Nullable();
CompositeId().KeyProperty(ch => ch.Region, "region")
.KeyProperty(ch => ch.Realm, "realm")
.KeyProperty(ch => ch.Name, "name");
HasMany<CharProgression>(ch => ch.Progression).Inverse().Cascade.All();
}
}
class CharProgressionMap : ClassMap<CharProgression>
{
public CharProgressionMap()
{
Table("char_progression");
CompositeId().KeyReference(cprog => cprog.Character, "char_id",
.KeyReference(cprog => cprog.Stage, "stage_id");
Id(cprog => cprog.Id, "id").GeneratedBy.Identity().Not.Nullable();
Map(cprog => cprog.ProgressionPoints, "progression_points");
Map(cprog => cprog.NumOfSaves, "num_of_saves");
}
}
public class StageMap : ClassMap<Stage>
{
public StageMap()
{
Table("stages");
Id(st => st.Id, "id").GeneratedBy.Identity().Not.Nullable();
Map(st => st.Name, "name");
Map(st => st.Description, "description");
}
}
Now, the thing is that I would like to use SaveOrUpdate() on a character and use the composite id for the update, since the character uniqueness is defined by those 3 fields - region, realm, name.
However, when I am referencing the Character from CharProgression, I don't want to use the composite Id as I don't want the char_progression table to hold 3 fields for identifying a character, a simple Id is enough... which is why I also defined an IDENTITY id on the Character entity.
Is what i'm trying possible? or is there another way to achieve this?
Thanks :)