4

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.

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
David
  • 204
  • 2
  • 9
  • 1
    *exactly what I want to prevent*, **Why**? – Salah Akbari Nov 21 '18 at 16:49
  • see edit - for performance reasons – David Nov 21 '18 at 16:51
  • 1
    adding a primary (clustered) key will actually improve performance significantly – DaniDev Nov 21 '18 at 17:54
  • I do have a primary key on Location, I want to store the attributes of Coordinate within the same table as Location. So I disagree, saving these attributes in the same table will be more efficient than storing them in a different table referencing them. Adding a key to Coordinate would create another table which would lead to more IOs for every single query. – David Nov 21 '18 at 22:03
  • 1
    I'm asking about the Annotation ComplexType, which promises to store attributes in the same table. – David Nov 21 '18 at 22:07
  • @David Check my updated answer out. I have proposed another solution. – Salah Akbari Nov 22 '18 at 07:43
  • Does the DB you're working with not have a suitable `geography` data type? For instance, SQL Server does and there are .NET types that support this too. – Damien_The_Unbeliever Nov 22 '18 at 07:58

2 Answers2

6

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.

David
  • 204
  • 2
  • 9
0

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

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109