I have two classes, Person and Event. Multiple people can sign up for an event and is coded as a foreign key list. My question is what is the correct way of adding an additional variable such as a paid bool or something? I imagine I will have to make a separate class with a foreign key link on both Person and Event but I wanted to make sure there wasn't some fancy way of adding an additional property.
If Person have many events then i would have structure my person class like below
public class Person
{
public int Id { get; set; }
// each person have many events
public List<EventRelation> Events { get; set; }
}
public class EventRelation
{
public int Id { get; set; }
public Events Event { get; set; }
// Person Id forgen Key
public int Person_Id { get; set; }
// Events Id forgen Key
public int Event_Id { get; set; }
}
public class Events
{
public int Id { get; set; }
public string EventType { get; set; }
}
Yes, you are doing it the right way. Since it's an N to N relationship, it needs a joining entity as you specified. The joining entity would have two primary (foreign key) properties including PersonId and EventId and other optional properties (in your case Paid).
Update:
Regarding looking for a fancy way, the answer is No. When designing a database, you are limited to the data model you are using which is relational data model here. EF and other kinds of ORMs are just tools for communications between the app and database.
However, if you define one foreign key in Person class with the type of Collection<Event> and another in Event class with the type of Collection<Person>, entity framework will automatically create the joining table with the two foreign keys. But it's not what you desire, because you need to add more properties to the joining table.
you can always add new properties into your class, execute migration script and then update database script in order to synchronise Entities with Database.
class Person
{
public int Id {get; set;}
}
suppose you add DateOfBirth
class Person
{
public int Id {get; set;}
public DateTime DateOfBirth {get; set;}
}
then
dotnet add migration 'BirthDate'
dotnet ef database update
Related
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 EF6 but...
I can not change the database.
So, if I'm not wrong, I need to create a model that suits the database.
I have to models in relationship one to many:
[Table("ReceCli")]
public class ReceCli
{
[Key]
public int Indice { get; set; }
[Required, StringLength(12)]
[Display(Name = "NÂș Documento")]
public string NDOC { get; set; }
[Display(Name = "Banco do boleto")]
[Column("CodBancoBoleto")]
public int CodBancoBoleto { get; set; }
public Banco Banco { get; set; }
}
and
[Table("Bancos")]
public class Banco
{
[Key]
public int CodBanco { get; set; }
[Column("Banco")]
[Required, StringLength(50)]
[Display(Name = "Banco")]
public string Nome { get; set; }
}
In the database this relations are expressing like:
ALTER TABLE [dbo].[ReceCli] WITH NOCHECK ADD CONSTRAINT [ReceCli_CodBancoBoleto] FOREIGN KEY([CodBancoBoleto])
REFERENCES [dbo].[Bancos] ([CodBanco])
GO
ALTER TABLE [dbo].[ReceCli] CHECK CONSTRAINT [ReceCli_CodBancoBoleto]
When executing return an error:
Invalid column name 'Banco_CodBanco'.
I can not change the database.
How can I change the model to EF use ReceCli_CodBancoBoleto name of column instead of Banco_CodBanco ?
You can do model an existing db by hand but you can also tell EF to generate the model from an existing database.
As for your example, a couple of things:
The relationship you have modeled is not one to many but one to one.
Public Banco Banco {get; set;}
Change To:
Public ICollection<Banco> Bancos {get;set;}
There are several ways you can model relationships with EF. Here's a sample of Modeling 1 to many relationships in EF.
The Column attribute is used to match to names in the DB. Make sure your EF CF properties that don't match the database have a Column Attribute. For Your RecCli it should look something like:
[Column("CodBanco")]
public int CodBancoBoleto { get; set; }
or
public int CodBanco { get; set; }
However, you are mapping a 1 to many relationship so having the CodBancoBoleto is not needed. Just use the navigation property of Public ICollection<Banco> Bancos {get;set;}. This should suffice except you might have to put a ForeignKey attribute for it telling it to use CodBanco as the key for the navigation.
[ForeignKey("CodBanco")]
Public ICollection<Banco> Bancos {get;set;}
You might have to do this for all your keys as the default code first convention for keys end with Id. I say might as your Banco Class's key is named properly CodBanco and marked with the Key. So you might be fine.
A final note is that you appear to be trying to use the constraints name for the mapping. You don't use the constraint name, rather the actual column names, aka the references part of the constraint.
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.
Considering the documentation here, you can define foreign key relationships in your pocos like the given example:
public class Customer
{
[References(typeof(CustomerAddress))]
public int PrimaryAddressId { get; set; }
[Reference]
public CustomerAddress PrimaryAddress { get; set; }
}
However, let's say that my CustomerAddress poco class actually has to be defined like this because someone decided to design the table like this a long, long time ago.
public class CustomerAddress
{
[PrimaryKey]
public int Id_1 { get; set; }
[PrimaryKey]
public string Id_2 { get; set; }
}
How can I properly define my [Reference] for the PrimaryAddress property in the Customer class with the composite key defined in CustomerAddress?
You can't using APIs that rely on it (but you can still use SELECT)
Please see OrmLite limitations.
I had same problem with a legacy database I can't modify (because another project cohabit with mine).
So I deleted primary key then created a new Id field (autoincrement) on the database (PK) and finally created a unique constraint (NOT NULLABLE) on both fields.
So now, I can use OrmLite to select properly without breaking compatibility with the other project.
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!)