I have an object that contains an attribute with the type of another object, which I want to treat as Complex Type.
public class Location : IModule
{
public string Id { get; set; }
public Coordinate Coordinate { get; set; }
}
[ComplexType]
public class Coordinate
{
public string Latitude { get; set; }
public string Longitude { get; set; }
}
While adding a migration, I ran into the problem that a primary key is required (exactly what I want to prevent).
The entity type Coordinate requires a primary key to be defined.
EDIT
For performance reasons I want the properties being stored as Coordinate_Latitude and Coordinate_Longitute instead of having a reference to another table.
Based on this question (How do I implement a simple "complex type" in Entity Framework Core 2/C#?), I found the answer: Owned entity types do the trick.
public class Location : IModule
{
public string Id { get; set; }
public Coordinate Coordinate { get; set; }
}
[Owned]
public class Coordinate
{
public string Latitude { get; set; }
public string Longitude { get; set; }
}
This creates a table containt the attributes Id, Coordinate_Latitued, Coordinate_Longitude.
You need to define a key, to make it works. This is how the Entity Framework works, Entity Framework needs to know the key to keep track on the object when you make an update or delete operation. Just if you don't want to manually insert it, you can declare it as an identity column to auto increment it. Something like this:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CoordinateKey { get; set; }
Or with Fluent-API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Coordinate>().HasKey(u => u.CoordinateKey);
modelBuilder.Entity<Coordinate>().Property(c => c.CoordinateKey)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
Edit: It seems you want to treat the Coordinate class as a not mapped class. You can use NotMapped attribute. Have a look at the following question to know how:
Entity Framework code first: How to ignore classes
Related
In EF Core 3.1 I am attempting to implement a Concurrency Token for my base class. I run into problems for entities stored in shared tables of which a derived class owns an entity. When the derived class holds a single property, it is advised to create this property as a shadow property on the base class. However with the property that represents an owned type I don't know how I can do this. I am trying to avoid putting in a shadow property for every single property in the owned type.
The class from which all entities are derived:
public class EntityClass
{
///...
[Timestamp]
public byte[] ConcurrencyToken { get; set; }
}
An example of a base class and the derived class that holds an additional owned type:
public class Transaction : EntityClass
{
///...
public Company Counterparty { get; set; }
public Currency TransactionCurrency { get; set; }
}
public class CashTransaction : Transaction
{
///...
public Currency BankAccountCurrency { get; set; }
}
Currency is an owned model and its properties are stored in the table related to Transaction:
[Owned, ComplexType]
public class Currency
{
///...
public string CurrencyName { get; set; }
public string CurrencySymbol { get; set; }
}
When I add the migration the following error shows:
Entity type 'CashTransaction.BankAccountCurrency#Currency' doesn't contain a property mapped to the store-generated concurrency token column 'ConcurrencyToken' that is used by another entity type sharing the table 'Transaction'. Add a store-generated property mapped to the same column to 'CashTransaction.BankAccountCurrency#Currency'. It can be in shadow state.
I tried to configure the shadow property with a few tries, for example:
modelBuilder.Entity<Transaction>().OwnsOne<Currency>("BankAccountCurrency");
EDIT:
Below does not work: it leads to issues with change tracking on derived class.
For a while I thought below would work: create a private property of the owned entity, and then configure this in the modelBuilder call:
public class Transaction : EntityClass
{
///...
public Company Counterparty { get; set; }
public Currency TransactionCurrency { get; set; }
private Currency BankAccountCurrency { get; set; }
}
modelBuilder.Entity<Transaction>().OwnsOne(typeof(Currency), nameof(CashTransaction.BankAccountCurrency));
I am using the table per hierarchy approach for achieving inheritance in entity types. I have 3 classes defined:
Room - Base class
SubMapRoom - Inherits from Room
OverviewRoom - Inherits from Room
In the DB, I just have 1 table called Room that has both the SubMapRoom and OverviewRoom columns in it. It also contains the Discriminator column for specifying which type it is.
First, I attempted to move all of the SubMapRoom columns in the Room class into the SubMapRoom class. 1 of the columns contains a foreign key to a different table called Status. After doing this, I tried specifying the foreign key relationship for the SubMapRoom entity type in OnModelCreating(). However, I get a compile error when I try to do this. In the EF Core OnModelCreating() method, I have this code (marked the line that contains the error below):
modelBuilder.Entity<SubMapRoom>(entity =>
{
entity.HasOne(d => d.UnassignedDoctorStatus)
.WithMany(p => p.Room) **ERROR HAPPENS HERE**
.HasForeignKey(d => d.UnassignedDoctorStatusId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("FK_Room_UnassignedStatusID");
});
modelBuilder.Entity<Room>()
.HasDiscriminator<int>("RoomType")
.HasValue<SubMapRoom>(1)
.HasValue<OverviewRoom>(2);
I get this error:
Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type
I know that I can solve this by changing the other class (Status) to use the inherited type instead of the base type for the navigation property, but that seems like the wrong way to go. I feel like I am missing something here. What would be the correct way to define a foreign key relationship in an inherited entity type?
[EDIT]
Here are the classes for the 4 models I have referenced here:
public abstract class Room
{
public Room()
{
InverseLinkedRoom = new HashSet<Room>();
}
public int Id { get; set; }
public int SubMapId { get; set; }
public string MapLabel { get; set; }
public string RoomLabel { get; set; }
public int LeftCoordinate { get; set; }
public int TopCoordinate { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int? LinkedRoomId { get; set; }
public int RoomType { get; set; }
public Room LinkedRoom { get; set; }
public SubMap SubMap { get; set; }
public PatientQueue PatientQueue { get; set; }
public ICollection<Room> InverseLinkedRoom { get; set; }
}
public class SubMapRoom : Room
{
public int? UnassignedDoctorStatusId { get; set; }
public Status UnassignedDoctorStatus { get; set; }
}
// Note: Have not yet attempted to move base class members in here
public class OverviewRoom : Room
{
}
public partial class Status
{
public Status()
{
Room = new HashSet<Room>();
}
public int Id { get; set; }
public string EnumId { get; set; }
public bool Active { get; set; }
public bool IsFastBlink { get; set; }
public ICollection<Room> Room { get; set; }
}
Thanks for the help everyone. I reviewed my DB schema and decided to make some changes that make this problem go away. It actually turns out that my new schema is easier to use in the code than I originally thought. In fact, it's a lot easier. I think I was trying to overengineer this. So sometimes, the solution is to review your schema and figure out if it even makes sense in the first place. Basically, what I did was move the inherited classes to a separate table with a separate ID. Because, at the end of the day, they are logically separate types of entities and only related in terms of the data. In the code, they serve much different purposes even though they share some of the same columns.
At the end of it all, the only disadvantage of this approach is that I am violating DRY on another table (there are 5 repeated columns in it). Otherwise, a lot of other operations are easier to code than before. I am willing to live with that instead of dealing with all of this for now. Later, I can try to use Table Per Hierarchy if I am having to add tons of new columns to both tables.
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 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?
In my AspNet MVC 3 project when I try to scaffold an entity which has a One to Zero or One relationship with another entity I get "An item with the same index has already been added" error.
Essentially this happens when the Primary Key of the related table is also a Foreign Key.
At the moment my workaround is
Add an Id column to the related table and make it the primary key
Add Unique Key to the Foreign Key Column.
The problem with this is that EF will generate an ICollection navigation property for the related entity instead of just a property of the related entity type (which I can set to null in case of zero related entities)
Is this a know bug?
Am I doing something wrong?
Is there a better work around to get rid of the ICollection navigation property?
See my answer on this question:
How do I code an optional one-to-one relationship in EF 4.1 code first with lazy loading and the same primary key on both tables?
That's the example code with the correct configuration.
public class ZoneMedia
{
public int ZoneMediaID { get; set; }
public string MediaName { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public virtual ZoneMediaText MediaText { get; set; }
}
public class ZoneMediaText
{
public int ZoneMediaID { get; set; }
public string Text { get; set; }
public int Color { get; set; }
public virtual ZoneMedia ZoneMedia { get; set; }
}
public class TestEFDbContext : DbContext
{
public DbSet<ZoneMedia> ZoneMedia { get; set; }
public DbSet<ZoneMediaText> ZoneMediaText { get; set; }
protected override void OnModelCreating (DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ZoneMedia>()
.HasOptional(zm => zm.MediaText);
modelBuilder.Entity<ZoneMediaText>()
.HasKey(zmt => zmt.ZoneMediaID);
modelBuilder.Entity<ZoneMediaText>()
.HasRequired(zmt => zmt.ZoneMedia)
.WithRequiredDependent(zm => zm.MediaText);
base.OnModelCreating(modelBuilder);
}
}
class Program
{
static void Main (string[] args)
{
var dbcontext = new TestEFDbContext();
var medias = dbcontext.ZoneMedia.ToList();
}
}
You can also achieve this with DataAnnotations, but I generally prefer to keep my entity models as POCOs.
Try to use the [Key] attribute to the intended primary key. You may need to import the namespace System.ComponentModel.DataAnnotations
Also check the documentation about the full implementation of this namespace.
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.aspx