This is similar to questions here and here, but those are old and have no good answers.
Let's say I have the following classes:
class HairCutStyle {
public int ID { get; set; }
public string Name { get; set; }
}
class CustomerHairCutPreference {
public int ID { get; set; }
public Customer Customer { get; set; }
public HairCutStyle HairCutStyle { get; set; }
}
Let's say my HairCutStyle data is stored in a table in another database (I get it from Paul Mitchell himself). I want to use the HairCutStyle class as a POCO class - something that I will use in code to represent hair cut styles, but I don't need to read/write that information in my database. (Assume I have a separate service layer that can populate the data for these classes from the other database.)
How can I tell EF NOT to create a HairCutStyle table in my current db context? But at the same time, I want to store a value in the CustomerHairCutPreference table that is a reference to the HairCutStyle data stored elsewhere. A "virtual" foreign key of sorts, that isn't constrained by an actual database FK constraint.
Add a property in CustomerHairCutPreference for HairCutSytleID and then use the [NotMapped] attribute on the HairCutStyle property. Note, however, that you will then be responsible for ensuring that the HairCutStyle and HairCutStyleID stay in sync.
class CustomerHairCutPreference {
public int ID { get; set; }
public Customer Customer { get; set; }
public int HairCutStyleID {get; set; }
[NotMapped]
public HairCutStyle HairCutStyle { get; set; }
}
Alternatively, you can use the FluentAPI to exclude HairCutStyle completely from ever being mapped by Entity Framework, which may be useful if you have multiple classes that link to it.
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Ignore<HairCutStyle>();
}
There are three things to ensure:
Make sure you do not expose a DbSet<HairCutStyle> in your DbContext-derived class
Make sure you do not have any mention of HairCutStyle in your OnModelCreating override
Mark your HairCutStyle property using the NotMapped attribute.
Related
I've got 2 entities with a 1-0..1 relationship between them, but restrictions on what the generated DB schema can look like.
So 1 Vehicle to 0 or 1 RecVehicle entity
I need to be able to have a navigation property from Vehicle to RecVehicle, but without the DB Schema for the Vehicles table having a FK to RecVehicle. The PK of the RecVehicle table should be the Id of the Vehicle entity it relates to.
We are using EF code first
public class Vehicle
{
[Key]
public int Id { get; set; }
public virtual RecVehicle RecVehicle { get; set; } // Need to be able to use as navigation
}
public class RecVehicle
{
[Key]
public int VehicleId { get; set; }
[ForeignKey("VehicleId")]
public Vehicle Vehicle { get; set; }
}
The generated schema needs to be something like this:
Vehicles
[ Id(int, pk, not null), ...] <-- no FK column to RecVehicles
RecVehicles
[ VehicleId(int, pk, fk, not null), ...]
Originally what I had tried something like this:
public class Vehicle
{
[Key]
public int Id { get; set; }
[InverseProperty("Vehicle")]
public virtual RecVehicle RecVehicle { get; set; } // Need to be able to use as navigation
}
but this causes this exception:
Unable to determine the principal end of an association between the types 'Contract.Entities.Vehicle' and 'Contract.Entities.RecVehicle'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I'm not sure what fluent API relationships to setup to make this work, nor the correct set of data annotations to make this work, or if it's even possible.
Reasoning
The reason there is strict limitations on the DB schema is our Data team has a migration/data import process that we can not alter
We have an existing code base that uses the navigation property in many places (2 teams, desync in schema) so changing to use a lookup in code requires many changes in the code base that we are trying to avoid.
The RecVehicle can be connected to multiple Vehicles
Can you try the following navigation property?
public virtual ICollection<RecVehicle> RecVehicle { get; set; }
instead of
public virtual RecVehicle RecVehicle { get; set; }
Due to the RecVehicle primary key this list only maximum contains one element
Ended up being able to get this relationship to work like this:
public class Vehicle
{
[Key]
public int Id { get; set; }
public virtual RecVehicle RecVehicle { get; set; }
}
public class RecVehicle
{
[Key]
public int VehicleId { get; set; }
[ForeignKey("VehicleId"), Required] //<--- Required attr fixed the principal/dependent confusion EF was having
public virtual Vehicle Vehicle { get; set; }
}
Suppose the following structure of classes and relationships:
class Document
{
public List<Version> DocumentVersions { get; set; }
// Other properties
}
class Register
{
public List<Version> RegisterVersions { get; set; }
// Other properties
}
class Version
{
public int VersionNumber { get; set; }
// Other properties
}
When using EF Core, it is going to produce 3 tables, D, R and V respectively where V is going to have 2 FK, one for D and one for R.
My questions are:
Is EF Core default approach correct? Wouldn't it lead to invalid states where V has no FKs because both FKs can be nullable.
I've read this and it almost answered my first question but it leads me to another question:
How can I tell EF to follow that approach: Should I have to create a derived type of V for each of its owners? or is there any way I can map a single entity to multiple tables and tell EF which relationships belong to which table?
Maybe is worth mention that my example is oversimplified and in reality I have 6 entities using the same V entity.
So, the dilemma is:
A) Should I keep two FKs in Version or
B) build two tables DocumentVersion and RegisterVersion instead of just Version?
Well, the truth is you can do both. You just have to decide which approach suits your system better. Let's have a quick look.
Approach A
To answer your question; yes EF's default approach is correct. Among creating two FKs and building two tables, it will create two FKs. It will create an extra table only in case of intermediate table for a many to many relashionship.
I always, though, recommend that we create all FKs ourselves instead of letting EF do it for us. This way we have more control over the behavior of the relationship and can also access the FKs in our application, since they are an entity's property.
public class Version
{
[Key]
public int VersionNumber { get; set; }
public int? DocumentID { get; set; }
public virtual Document Document { get; set; }
public int? RegisterID { get; set; }
public virtual Register Register { get; set; }
//Other properties
}
Since Version has a PK, it can create records without any of the FKs having any value. If this is allowed in your business model then leave it as it is. You can later provide a UI to assign "Versions" to either "Documents" or "Registers".
If you want to add some rules in your Version table; for example each record should have at least one FK or only one FK, you can do that by overriding the ValidateEntity method of your DbContext class (or through some sql constraint in the database probably).
protected override DbEntityValidationResult ValidateEntity(
DbEntityEntry entityEntry, IDictionary<object, object> items)
{
// validate entity from annotations
var result = base.ValidateEntity(entityEntry, items);
// custom validation rules
if (entityEntry.Entity is Version &&
(entityEntry.State == EntityState.Added || entityEntry.State == EntityState.Modified))
{
Version version = ((Version)entityEntry.Entity);
if (version.DocumentID == null && version.RegisterID == null)
result.ValidationErrors.Add(new DbValidationError(null, "A document or register must be specified."));
}
return result;
}
Note that you can create your own annotations to validate your entity properties. But these are restricted to a single property. If you want to add validations that combine more than one property, the ValidateEntity method is the only way I know of.
Approach B
There are two ways to implement this approach. The first is to keep the Version table and add two intermediate tables on top.
public class Document
{
public virtual List<DocumentVersion> Versions { get; set; }
// other properties
}
public class Register
{
public virtual List<RegisterVersion> Versions { get; set; }
// other properties
}
public class Version
{
[Key]
public int VersionNumber { get; set; }
//Other properties
}
public class DocumentVersion
{
public int DocumentID { get; set; }
public virtual Document Document { get; set; }
public int VersionID { get; set; }
public virtual Version Version { get; set; }
// other properties
}
public class RegisterVersion
{
public int RegisterID { get; set; }
public virtual Register Register { get; set; }
public int VersionID { get; set; }
public virtual Version Version { get; set; }
// other properties
}
This actualy allows a many-to-many relationship, but you can use it as a one-to-many.
The second way is to make Version abstract (not a database table) and build two new tables to inherit from Version:
public class Document
{
public virtual List<DocumentVersion> Versions { get; set; }
// other properties
}
public class Register
{
public virtual List<RegisterVersion> Versions { get; set; }
// other properties
}
// don't make this a DbSet
public abstract class Version
{
[Key]
public int VersionNumber { get; set; }
//Other properties
}
public class DocumentVersion : Version
{
public int DocumentID { get; set; }
public virtual Document Document { get; set; }
// other properties
}
public class RegisterVersion : Version
{
public int RegisterID { get; set; }
public virtual Register Register { get; set; }}
// other properties
}
This is a proper and clear one-to-many relationship.
Conclusion
The bottom line is that you can use any of the two approaches and with alterations that suit your needs.
I have used both approaches successfully, but I tend to prefer the second one (and with the abstract class inheritance). The first approach seems more of a way to cut down on database resources or ease of development, but modern databases are not at all stressed by a few tables more and the development could become unnecessarily complex. Further more the second approach allows to extend the functionality of the relationships by adding further properties to each connection table seperatelly. And for the 6 entities you have to deal with, it seems safer to me to go with the second approach. I have used this approach in an application with many file types and relationships and it was always very straight-forward and extendable. Those extra properties in each relashion table came very handy too.
Hope I could help,
merry coding!
I don't think this really is a one-to-many relationship, look here.
It would be a one-to-many relationship if (for example) Document had multiple (e.g. a list of) Versions.
If you want multiple entities refering to the same entity type, you could place the foreign keys explicitly in the Document and Register classes:
class Document
{
public Version DocumentVersion { get; set; }
public int DocumentVersionId { get; set; } // Or whatever datatype your ID is
// Other properties
}
class Register
{
public Version RegisterVersion { get; set; }
public int RegisterVersionId { get; set; } // Or whatever datatype your ID is
// Other properties
}
class Version
{
public int VersionNumber { get; set; }
// Other properties
}
I'm in a situation where one table has two One-None/One Relationships. How do I implement this using Entity Framework Code-First?
I've seen the following links
https://www.safaribooksonline.com/library/view/programming-entity-framework/9781449317867/ch04s07.html
https://cpratt.co/0-1-to-1-relationships-in-entity-framework/
https://www.tektutorialshub.com/one-to-one-relationship-entity-framework/
Where essentially it's said that the dependent end needs to have a primary key that is the same as that of the principal end. But I'm weary of implementing this with more than one One-None/One Relationship without confirmation and proper knowledge of what's going on. Furthermore I am not sure how to construct statements as it does not have a conventional Foreign Key.
I've also seen Configuring multiple 1 to 0..1 relationships between tables entity framework which confused me beyond recognition.
See below for the relevant part of my DB Diagram:
So Essentially, a Player shouldn't be saved without a DKImage, similarly a Product shouldn't be saved without a DKImage.
Below is the code for Models: Players, Products, DKImages (I know it's not correct, I only implemented it this way so I can generate the database and show the diagram)
Player
public enum Positions { PG, SG, SF, PF, C }
public class Player
{
[Key]
[ForeignKey("Images")]
public int PlayerID { get; set; }
[Required]
public string PlayerName { get; set; }
[Required]
public string PlayerLastName { get; set; }
[Required]
public int PlayerAge { get; set; }
[Required]
public Positions Position { get; set; }
[Required]
public bool Starter { get; set; }
[Required]
[Display(Name = "Active / Not Active")]
public bool Status { get; set; }
//Foreign Keys
public int PlayerStatsID { get; set; }
//Navigation Properties
[ForeignKey("PlayerStatsID")]
public virtual IQueryable<PlayerStats> PlayerStats { get; set; }
public virtual DKImages Images { get; set; }
}
DKImages
public class DKImages
{
[Key]
public int ImageID { get; set; }
[Required]
public string ImageURL { get; set; }
[Required]
public DateTime DateUploaded { get; set; }
//Foreign Keys
[Required]
public int CategoryID { get; set; }
//Navigation Properties
public virtual Products Products { get; set; }
public virtual Category Category { get; set; }
public virtual Player Player { get; set; }
}
Products
public class Products
{
[ForeignKey("Images")]
[Key]
public int ProductID { get; set; }
[Required]
public string ProductName { get; set; }
[Required]
public DateTime DateAdded { get; set; }
//Foreign Keys
[Required]
public int ProductTypeID { get; set; }
//Navigation Properties
[ForeignKey("ProductTypeID")]
public virtual ProductType ProductType { get; set; }
public virtual DKImages Images { get; set; }
}
Edit
I have been told that the code above is correct. If so then how do I create CRUD LINQ Statements (Or any method of constructing CRUD statements for that matter) with the above code.
What you want here is referred to as polymorphic associations: several entities having child entities of one type. They're typically used for comments, remarks, files etc. and usually applied to 1:n associations. In your case there are polymorphic 1:1 associations. Basically these associations look like this (using a bit more generic names):
How to implement them?
Entity Framework 6
In EF6 that's problem. EF6 implements 1:1 associations as shared primary keys: the child's primary key is also a foreign key to its parent's primary key. That would mean that there should be two FKs on Image.ID , one pointing to Person.ID and another one pointing to Product.ID. Technically that's not a problem, semantically it is. Two parent entities now own the same image or, stated differently, an image should always belong to two different parents. In real life, that's nonsense.
The solution could be to reverse the references:
But now there's another problem. The entity that's referred to is named the principal, the other entity is dependent. In the second diagram, Image is the principal, so in order to create a Person, its image must be inserted first and then the person copies its primary key. That's counter-intuitive and most likely also impractical. It's impossible if images are optional.
Nevertheless, since in your case you want images to be required let me show how this association is mapped in EF6.
Let's take this simple model:
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public virtual Image Image { get; set; }
}
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public virtual Image Image { get; set; }
}
public class Image
{
public int ImgID { get; set; } // Named for distinction
public string Url { get; set; }
}
The required mapping is:
modelBuilder.Entity<Image>().HasKey(pd => pd.ImgID);
modelBuilder.Entity<Person>().HasRequired(p => p.Image).WithRequiredDependent();
modelBuilder.Entity<Product>().HasRequired(p => p.Image).WithRequiredDependent();
As you see, Image has two required dependents. Perhaps that's better than two required parents, but it's still weird. Fortunately, in reality it's not a problem, because EF doesn't validate these associations. You can even insert an image without a "required" dependent. I don't know why EF doesn't validate this, but here it comes in handy. The part WithRequiredDependent might as well have been WithOptional, it doesn't make a difference for the generated data model, but at least this mapping conveys your intentions.
An alternative approach could be inheritance. If Person and Product inherit from one base class this base class could be the principal in a 1:1 association with Image. However, I think this is abusing a design pattern. People and products have nothing in common. From a design perspective there's no reason for them to be part of one inheritance tree.
Therefore, in EF6 I think the most feasible solution is to use the third alternative: separate image tables per entity.
Entity Framework Core
In EF-core 1:1 associations can be implemented the EF6 way, but it's also possible to use a separate foreign key field in the dependent entity. Doing so, the polymorphic case looks like this:
The Image class is different:
public class Image
{
public Image()
{ }
public int ImgID { get; set; }
public int? PersonID { get; set; }
public int? ProductID { get; set; }
public string Url { get; set; }
}
And the mapping:
modelBuilder.Entity<Person>().Property(p => p.ID).UseSqlServerIdentityColumn();
modelBuilder.Entity<Person>()
.HasOne(p => p.Image)
.WithOne()
.HasForeignKey<Image>(p => p.PersonID);
modelBuilder.Entity<Product>().Property(p => p.ID).UseSqlServerIdentityColumn();
modelBuilder.Entity<Product>()
.HasOne(p => p.Image)
.WithOne()
.HasForeignKey<Image>(p => p.ProductID);
modelBuilder.Entity<Image>().HasKey(p => p.ImgID);
Watch the nullable foreign keys. They're necessary because an image belongs to either a Person or a Product. That's one drawback of this design. Another is that you need a new foreign key field for each new entity you want to own images. Normally you want to avoid such sparse columns. There's also an advantage as compared to the EF6 implementation: this model allows bidirectional navigation. Image may be extended with Person and Product navigation properties.
EF does a pretty good job translating this into a database design. Each foreign key has a filtered unique index, for example for Person:
CREATE UNIQUE NONCLUSTERED INDEX [IX_Image_PersonID] ON [dbo].[Image]
(
[PersonID] ASC
)
WHERE ([PersonID] IS NOT NULL)
This turns the association into a genuine 1:1 association on the database side. Without the unique index it would be a 1:n association from the database's perspective.
An exemple in your Player table would be this :
public class Player
{
// All the rest you already coded
[Required]
public int ImageID
[ForeignKey("ImageID")]
public virtual DKImage DKImage {get;set;}
}
This would force a player to have a DKImage, but as said in the comments, this create a one to many relationship.
Another way out would be to put all Player fields into the DKImage table, those fields would be null if there is no player associated to this DKImage.
Edit for 1 to 1..0
Ivan Stoev's link got some pretty interesting insight on how to accomplish this :
https://weblogs.asp.net/manavi/associations-in-ef-4-1-code-first-part-3-shared-primary-key-associations
It seems like you will have to put a bit more code in your class :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DKImage>().HasOptional(t => t.Player).WithRequired();
}
If the tutorial is correct, this would read as :
"DKImage entity has an optional association with one Player object but this association is required for Player entity".
I have not tested it yet.
I am using EF Core 2.0 in my project.
I have the table schema as somewhat like this:
Table: Report
Id int
Name varchar
Description varchar
<ExtraColumn> <sometype>
And my model class would probably be like this:
class Report
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public <sometype> <SomeProperty> { get; set; }
}
In my project, I don't want to use some columns in the table in the EF mapping. So, I would like to exclude it from the entity mapping.
Similarly, I want to use some properties in the model class for other internal purposes (not for EF mapping).
Is this possible at all?
P.S. I have heard that the Ignore() method in EF Core addresses the second requirement of mine. But, what about the first one?
Is there a way out?
By convention, public properties with a getter and a setter will be included in the model.
You can use Data Annotations or Fluent API to exclude a property from the model.
Data Annotation:
class Report
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
[NotMapped]
public <sometype> <SomeProperty> { get; set; }
}
Fluent API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Report>()
.Ignore(b => b.<SomeProperty>);
}
I have an entity called Asset, similar to below:
public class Asset
{
public int Id { get; set; }
public int TypeId { get; set; }
public int AddedById { get; set; }
public DateTime DateTimeAdded { get; set; }
public virtual AssetType Type { get; set; }
public virtual ITUser AddedBy { get; set; }
}
I want to be able to have a navigation property that is linked to a single table, but that table is dependent on what type of Asset it is. For instance, if the Asset is of the type "Printer" then I want the navigation property to link to the PrinterDetail entity. My initial way of going about this was to have unused columns in the Asset entity, but I figured that was wasteful or bad practice. Is there something that I am overlooking or is this just something that cannot be done?
Thanks for any advice given.
if you want navigate printerDetail by type you can use entityfraemwork inheritance strategy:
Table per Hierarchy (TPH)
Table per Type (TPT)
Table per Concrete class (TPC)
you have to create Model per each type and use TPT strategy for that.
and then you can use fluent api for config mapping for that.
parent Model (Asset) must define as abstract class and AssesTypes Must be Drive from the Parent.
more information