I have this POCO class :
public class MyClass
{
public int MyKey { get; set; }
public string Name { get; set; }
public bool DiscriminatorField { get; set; }
public string AnotherInfo { get; set; }
}
My database model is as such :
Main
ID int
Name varchar
DiscriminatorField bit
Specific1
ID int
AnotherField varchar
Specific2
ID int
AnotherField varchar
The question: Using fluent API (and most likely EntityTypeConfiguration), how can I create this conditional mapping where AnotherField of my entity gets filled by Specific1 if the discriminator is true, and by Specific2 if the discriminator is false?
Note: I do not want to create two different POCOs. I'm looking for something like this, but conditional.
Edit: Added the discriminator field to the POCO entity.
Related
Few days ago I switch (due to my student project) to Entity Framework and I have to develop Entity whos foreign key will depend of ENUM value , I spend last two day trying to figure it out but unfortunately I was not able to figure it out , so I hope someone here will be able to help me with it :)
Seller.cs
Public int Id {get;set}
public string FullName {get;set}
public string Country {get;set}
public int CentralizationId {get;set}
[ForeignKey("CentralizationId"}
public Centralization Centralization {get;set;}
Buyer.cs
Public int Id {get;set}
public string FullName {get;set}
public string Country {get;set}
public CurrencyType CurrencyType {get;set;}
public int CentralizationId {get;set}
[ForeignKey("CentralizationId"}
public Centralization Centralization {get;set;}
Centralization.cs
public int Id { get; set; }
public int AuthorId { get; set; }
[ForeignKey("UserId")]
public Author Author { get; set; }
public Type Type { get; set; }
[ForeignKey("TypeId")]
public int TypeId { get; set; }
public enum Type
{
Selling = 1,
Buying = 2,
}
So basically what I need is that if Type = 1 on typeId to be Seller.Id where later via getAllIncluding I will be able to get his date (somehow typeId should depend on Type)
I tried using Getters and Setters but didn`t help at all
How I think at the end should looks like for example :
Type = 1 (Selling)
[ForeignKey("TypeId")]
public Seller typeId {get;set;}
Hope someone here will be able to help me :)
Have a nice day !
You can use an Enum for a FK/PK. EF will typically treat this as an int in the database.
For instance if in a database I want a "Type" table with an TypeId to enforce referential integrity but I don't necessarily want a "Type" entity, I just want an enumeration to represent that type:
public enum Type
{
None = 0,
Buying = 1,
Selling = 2
}
public class Something
{
public int Id { get; set; }
// ...
[Column("TypeId")]
public Type Type { get; set; }
}
I would recommend a name that is more descriptive than just "Type" to avoid naming collisions with system types. I.e. "OrderType", "TransactionType" etc.
The [ForeignKey] attribute is used to nominate the FK fields for relationships between entities. In this case we aren't using an entity, but an enumeration so we just use [Column] to tell EF what the column should be named.
The above works for DB-First implementations. If you want to use Code-First where the EF definitions will be responsible for creating the schema, you will need to manually add migrations to create the "Type" table and set up the FK between it and your other table. Otherwise EF will merely leave that TypeId column as a regular column on the "Something" table.
Alternatively you can use Enums as a FK/PK which can allow you to define additional properties to go along with the relationship, and let Code First manage the table relationships as well:
public enum TypeIds
{
None = 0,
Buying = 1,
Selling = 2
}
public class Type
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public TypeIds TypeId { get; set; }
public string Description { get; set; }
}
public class Something
{
[Key]
public int Id { get; set; }
// ...
[ForeignKey("Type")]
public TypeIds TypeId { get; set; }
public virtual Type Type { get; set; }
}
This allows you to use the Enumeration as both a PK of an entity containing relevant details about the enumeration, and as the FK within the related entities.
Enumerations as PK/FK are useful in cases where you might have business logic dependent on those states. The important thing to consider with enumerations is that the Application rather than the database should be in control of the ID assignment, hence the use of [DatabaseGenerated(DatabaseGeneratedOption.None)] on the PK of our Type entity/table. This tells EF that the database should not use an Identity but rely on the consumer (our code) to set these IDs. We want to ensure that it is as clear as possible that our Enum is the source of truth for these keys.
I’m trying to model a relationship between two tables in an existing MsSQL Db using EF Core, but the Db has tables using custom table names and column names.
EF Core is failing to setup the relationship, even though I’m specifying the relationship using either attributes or FluentAPI.
I think the problem is because I have non-convention names for tables and columns and EF is failing to setup the relationship properly.
Here’s the SQL:
CREATE TABLE paid_authors
(
paid_author_id varchar(50) NOT NULL,
[name] varchar(50) NOT NULL
)
CREATE TABLE hardback_books
(
hardback_book_id uniqueidentifier NOT NULL,
paid_author_id varchar(50) NOT NULL,
title varchar(50) NOT NULL
)
INSERT INTO paid_authors VALUES ('duck' ,'Scrooge McDuck')
INSERT INTO hardback_books VALUES (NEWID(), 'duck', 'Duck Tales')
Here’s the C# modelling:
[Table("paid_authors")]
public class PaidAuthor
{
[Key]
[Column("paid_author_id")]
public string PaidAuthorId { get; set; }
[Column("name")]
public string Name { get; set; }
public virtual List<HardbackBook> HardbackBooks { get; set; }
}
[Table("hardback_books")]
public class HardbackBook
{
[Key]
[Column("hardback_book_id")]
public Guid HardbackBookId { get; set; }
[Column("title")]
public string Title { get; set; }
[ForeignKey("HardbackBooks")] // This could be wrong!
[Column("paid_author_id")]
public string PaidAuthorId {get; set;}
}
My code:
foreach(var author in context.PaidAuthors.Take(10))
{
// This next line makes it work, but it shouldn’t be needed!
// author.HardbackBooks = context.HardbackBooks.Where(x => x.PaidAuthorId == author.PaidAuthorId).ToList();
Console.WriteLine(author.PaidAuthorId + " - " + author.Name);
Console.WriteLine(author.HardbackBooks.Count);
}
When I run the code I get System.NullReferenceException and author.HardbackBooks is null.
I’ve tried FluentAPI, specifying the ForeignKey on the parent class... But there must be something obvious I’m missing! I'm happy to switch to FluentAPI if it can be made to work there.
Needless to say, I can't change the Db structure... :-(
You can't leave the collection Navigation Property null, and should have an inverse Navigation Property on the book. Something like:
[Table("paid_authors")]
public class PaidAuthor
{
[Key]
[Column("paid_author_id")]
public string PaidAuthorId { get; set; }
[Column("name")]
public string Name { get; set; }
public virtual List<HardbackBook> HardbackBooks { get; } = new HashSet<HardbackBook>();
}
[Table("hardback_books")]
public class HardbackBook
{
[Key]
[Column("hardback_book_id")]
public Guid HardbackBookId { get; set; }
[Column("title")]
public string Title { get; set; }
public PaidAuthor PaidAuthor { get; set; }
[ForeignKey("PaidAuthor")]
[Column("paid_author_id")]
public string PaidAuthorId { get; set; }
}
I have some data class generated from the DB:
[Table("appdb.apptable")]
public partial class apptable
{
[Key]
public int Id { get; set; }
public int Sum { get; set; }
public string Comment { get; set; }
}
How, I need to support different table in a generic way.
The table name the same, but it does not contain Comment field.
I need somehow to make the Comment property optional.
How can I make an existent DB field optional in Entity Framework?
Is there an attribute I can use when creating a table ? I tried [StringLength] but it seems to be ignored.
public class EntityRegister
{
public int Id { get; set; }
[StringLength(450)]
public string Name { get; set; }
}
alternatively, you can manually do it on Fluent API
use HasMaxLength(450)
Configuring Properties and Types with the Fluent API
EF 6
EF Core
or if you want Data Annotation, use MaxLength and MinLength attributes
public class EntityRegister
{
public int Id { get; set; }
[MaxLength(450)]
public string Name { get; set; }
}
Code First Data Annotations
Suppose you have
public class A
{
public string _myString;
}
And this context:
public class MyContext: DbContext
{
public DbSet<A> myASet{ get; set; }
}
Now, is there a way to tell EF to generate an identity column for myASet?
I don't want to add an ID field to class A, so I wonder if EF could do this.
Many thanks,
Juergen
You must add ID column to your class if you want to have it in the database. Also in EF each entity must have mapped primary key.
EF will only use columns which are actually in your model classes, so you have to put all the ones you want in yourself. This includes identity columns for primary keys.
If you have an entity called Product and a property called 'ProductId' , EF will automatically add the identity column as it looks for entity name + Id by convention.
You can use a column that does not comply with the convention by adding a [key] attribute above the desired property.
In the example below. An identity column will be created for ProductId.
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
In this example, the column 'MyId' will be created as an identity.
public class Product
{
[key]
public int MyId { get; set; }
public string Name { get; set; }
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}