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.
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; }
}
I need to implement Entity-Attribute-Value functionality on multiple data tables using Entity Framework. Let's say I have an attribute value EF class that looks like this:
public class EntityAttributeValue
{
// Not important to my question.
public virtual Entity ParentEntity { get; set; }
public virtual EntityAttribute ParentEntityAttribute { get; set; }
// Field in question.
public Guid ParentSurrogateKey { get; set; }
public string Value { get; set; }
...
}
Then I have multiple entities that have supplementary EAV values associated with them:
public class Entity1
{
// Key. EntityAttributeBalue.ParentSurrogateKey maps to this.
[Key]
public Guid SurrogateKey { get; set; }
// Standard properties.
public string Property1 { get; set; }
public string Property2 { get; set; }
// Collection of EAV values associated with this entity/table.
[ForeignKey("ParentSurrogateKey")]
public virtual IList<EntityAttributeValue> EntityAttributeValues { get; set; }
}
public class Entity2
{
// Key. EntityAttributeBalue.ParentSurrogateKey maps to this.
[Key]
public Guid SurrogateKey { get; set; }
// Standard properties.
public string OtherProperty1 { get; set; }
public string OtherProperty2 { get; set; }
// Collection of EAV values associated with this entity/table.
[ForeignKey("ParentSurrogateKey")]
public virtual IList<EntityAttributeValue> EntityAttributeValues { get; set; }
}
My problem is that both Entity1 and Entity2 have EntityAttributeValue objects associated with them. Code first migrations tries to create a foreign key from EntityAttributeValue back to Entity1 and another one back to Entity2 on ParentSurrogateKey. The surrogate key for any single given EntityAttributeValue is only associated with either one Entity1 or one Entity2 (or, expanding out, one EntityN...), not both/all.
I have a many to many relationship here, but one side not only maps to multiple rows, but multiple entities/tables over a shared GUID column.
How should I be approaching this? Should I just remove the EntityAttributeValue foreign keys back to Entity1 and Entity2 from the automatic migration (which would be a long term pain)? Should I be manually retrieving the list of EntityAttributeValues for a given EAV entity instead of relying on EF to do it for me?
Well, the answer turned out to be obvious and simple. I needed to define a many-to-many relationship with FluentAPI. In OnModelCreating, I just added:
modelBuilder.Entity<Entity1>()
.HasMany(m => m.EntityAttributeValues)
.WithMany();
modelBuilder.Entity<Entity2>()
.HasMany(m => m.EntityAttributeValues)
.WithMany();
I thought I had tried this, but I guess I hadn't. Because the many-to-many relationship creates an intermediate table for each entity and the foreign keys are on that intermediate table (and there is only a row in the intermediate table when a given EntityAttributeValue applies to a given Entity), no foreign key issues.
I currently have a situation with code first EF6 where I need to create a many-to-many mapping (easy enough) however the generated relationship table needs to contain properties of its own. Here's a simplified example of what I have:
public class Journey : Entity
{
public string Name { get; set; }
public DateTime Start { get; set; }
public virtual ICollection<Point> Points { get; set; }
}
public class Point : Entity
{
public DbGeography GeoLocation { get; set; }
public string Name { get; set; }
public virtual ICollection<Journey> Journeys { get; set; }
}
The "Entity" class basically contains the primary key.
This would of course create a relationship table with foreign keys for the "Point" and "Journey" table primary keys. Great, but what if I want to add properties to that link table? Such as a DateTime property called ArrivalDate which holds the time of arrival at that point.
You could argue that I can add that property to the "Point" class but I want this table to hold a list of all physical points used in my application, without duplicates (a single point could be used in multiple journeys, each with different arrival dates). Therefor I need to hold this property elsewhere, the link table would be ideal here.
The only solution I can think of would be to create an actual relationship class:
public class JourneyPoint : Entity
{
public int JourneyId { get; set; }
public int PointId { get; set; }
public DateTime ArrivalTime { get; set; }
public virtual Journey Journey { get; set; }
public virtual Point Point { get; set; }
}
And then modify my Journey and Point classes to have a one-to-many relationship with the JourneyPoint class. However this just adds complication and isn't particularly semantic:
...
Journey myJourney = aMethodToGetMyJourney();
Point firstPoint = myJourney.JourneyPoints[0].Point.
...
That doesn't seems to make much sense and could confuse other developers. Is what I'm asking for possible at all?
I have a table in the database that has 4 foreign keys referencing to it. When I add the table to the edmx, the table and navigational properties are there. However, the foreign key ids from this table is missing and only the virtual objects are there.
This is the following table that is generated in the .tt file:
public partial class Device
{
public int SolutionId { get; set; }
public string SiteId { get; set; }
public string Name { get; set; }
public int SysId { get; set; }
public Nullable<int> SysType { get; set; }
public string SerialNumber { get; set; }
public Nullable<int> ParentId { get; set; }
public virtual DeviceModel DeviceModel { get; set; }
public virtual DeviceType DeviceType { get; set; }
public virtual SolutionApplication SolutionApplication { get; set; }
public virtual SolutionType SolutionType { get; set; }
}
There are a few members missing:
DeviceModelId, DeviceTypeId, SolutionApplicationId, and SolutionTypeId
Why is it missing? Is there any way to get those keys actually be part of the partial class?
using EntityFrameworks v6.0.2. Lazy Loading
In short, Entity Framework 'abstracts that away'.
Its clever enough to recognise that your FKs represent relationships and so allows you to work with the objects themselves. So instead of having you worry about checking the FK constraint, etc. for, say, SolutionTypeId - you just need to add a SolutionType object to your Device object and let Entity Framework sort it out. (Of course, this causes problems if you try to add a new SolutionType that violates the SolutionType PK so maybe you need to first find an existing object from the SolutionTypes table).
So, instead of thinking of it as a Device table linked to a SolutionType table via a FK - just think of it as a Device object with a SolutionType object as a property. EF sorts out the db for you when you save changes (assuming your model is accurate!)
I'm trying to learn NHibernate 3.2 built-in mapping by code api (NOT Fluent NHibernate). Can you help me to map a one-to-one(or zero) relationship between these entities please?
NOTE: I googled the question, also I search the SOF, all examples are using Fluent API or XML; I'm trying to use built-in mapping API in NHibernate 3.2
public class Person {
public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
// can be null
public virtual Address Address { get; set; }
}
public class Address {
public virtual int Id { get; set; }
public virtual string Line1 { get; set; }
public virtual string Line2 { get; set; }
public virtual string City { get; set; }
// can not be null
public virtual Person Person { get; set; }
}
Primary key strategy is here:
Id(
t => t.Id,
t => {
t.Generator(Generators.HighLow, g => g.Params(new { max_low = 100 }));
t.Column(typeof(TEntity).Name + "Id");
});
Depending on what you ACTUALLY want- a one-to-one map or a many-to-one map may answer your question. Please see this link for one-to-one if you need a truly unique bi-directional constraint: http://notherdev.blogspot.com/2012/01/mapping-by-code-onetoone.html
One-to-ones are normally a bad strategy because it makes sense to just put the columns all on one table in almost all cases, and separate them via a component mapping if you need them to be separate entities in your domain. The typical way to separate them in the domain AND the data models is to use a many-to-one with a unique constraint tying back up to the parent and this is a common pattern.
For tips and hints on general 3.2 mappings, this resource has been a ton of help for me: http://notherdev.blogspot.com/2012/02/nhibernates-mapping-by-code-summary.html