Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complex types and/or value objects #246

Closed
rowanmiller opened this issue May 22, 2014 · 112 comments
Closed

Complex types and/or value objects #246

rowanmiller opened this issue May 22, 2014 · 112 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Milestone

Comments

@rowanmiller
Copy link
Contributor

This issue is tracking the inclusion of support for either complex types and/or value objects in EF7.x (we haven't decided what form exactly this will take or when we will do it but it is not planned for EF7.0.0 RTM).

Complex Type just means a class with no primary key - i.e. it's just a way of organizing some properties that are part of the object it is referenced from. This has been called complex types traditionally in EF.

Value objects also can be seen as a set of properties grouped under the same type that don't have a key, although there is a more formal definition and characteristics, e.g. they should be immutable, equality should be defined the values of their individual properties rather than on a key, copy value semantics is desirable.

When doing this we should consider different strategies for how the data is stored. In EF6 we had a column in the parent table for each property in the complex type. Another strategy that folks may want to chose if serializing the data as JSON/XML etc. (see #3486)

@npehrsson
Copy link

Is there a plan for when this will be implemented?

@rowanmiller
Copy link
Contributor Author

@npehrsson no exact timeline at the moment. It's high on the backlog, close behind TPH inheritance support and navigation property translation in LINQ (which are both being implemented at the moment).

kirthik added a commit that referenced this issue Aug 14, 2015
@CreepyGnome
Copy link

Will this make it into Beta 7? Beta 8? RC? If not by RC I would assume it isn't making it by RTM.

This feature has been lacking since the beginning of EF and yet has been in competitive alternatives. Without this feature EF7 will still be at a competitive disadvantage. This is a huge feature to allow people to create data models naturally for their domains without having to shoe horn them into compatible types supported by EF.

@rowanmiller
Copy link
Contributor Author

@CreepyGnome correct, this one is triaged for post initial stable release. This would definitely fall into the bucket of features that means EF6.x will be the right choice for many apps for a while.

@CreepyGnome
Copy link

First what do you guys mean by Complex Types here?

What I mean are the ones within the .NET Framework like IDictionary, ILookup, Money, etc. I wasn't worried EF7 supporting my POCO Entities and nesting Entities within other Entities. However now I am concerned.

Technically all Domain Models are nothing but a hierarchy of Custom Complex Types that we typically like to call POCOs. I would have to say supporting custom complex types like these are mandatory for any ORM otherwise what are you mapping really? However your answer makes me think EF7 will be like EF5 and lower when it comes to any Complex Type and Nesting of them. If so that is a huge step backwards.

So are you saying EF7 doesn't support ANY complex types what so ever bet that .NET Framework or custom ones you create? If so that means EF7 doesn't supporting nesting of entities.

Also am I to assume that if it is flagged as being in the backlog, them it means no release is targeted at this time period.

@npehrsson
Copy link

I thought this was value objects, value objects = complex type in ef6, not
sure why they didn't call it value object mapping. And I agree not
supporting this is a pain for us that want to use the beta.
On Aug 25, 2015 12:36 AM, "Rodney S. Foley" notifications@github.com
wrote:

First what do you guys mean by Complex Types here?

What I mean are the ones within the .NET Framework like IDictionary,
ILookup, Money, etc. I wasn't worried EF7 supporting my POCO Entities and
nesting Entities within other Entities. However now I am concerned.

Technically all Domain Models are nothing but a hierarchy of Custom
Complex Types that we typically like to call POCOs. I would have to say
supporting custom complex types like these are mandatory for any ORM
otherwise what are you mapping really? However your answer makes me think
EF7 will be like EF5 and lower when it comes to any Complex Type and
Nesting of them. If so that is a huge step backwards.

So are you saying EF7 doesn't support ANY complex types what so ever bet
that .NET Framework or custom ones you create? If so that means EF7 doesn't
supporting nesting of entities.

Also am I to assume that if it is flagged as being in the backlog, them it
means no release is targeted at this time period.


Reply to this email directly or view it on GitHub
#246 (comment)
.

@rowanmiller
Copy link
Contributor Author

Hey,

Complex Type just means a class with no primary ke - i.e. it's just a way of organizing some properties that are part of the object it is referenced from. They have historically been called "Complex Types" in EF (before my time) but I think most folks would expect a value type to be immutable (which complex types are not - though you can make the property setters private to somewhat achieve this).

Correct that this will not be in the November RC. We haven't allocated any work items to release beyond that. This is listed on our roadmap as a critical O/RM feature and something we need implemented before we start saying that EF7 is a serious alternative to EF6 for all apps.

~Rowan

@CreepyGnome
Copy link

What you described as a complex type is broad and to support that would be difficult, unless supported the way EF6 claims to support a much more limited version of Complex Types definition.

I mean a Dictionary and other core classes, don't have ID's and yet are complex types but was never supported before in EF, but is supported by others ORMs. If EF7 is only trying to be at the same level as EF6 with this feature request here, is there another feature in the backlog for support things like Dictionary<TKey, TElement>, Lookup<TKey, TElement>, HashSet, (all collections basically, Money, etc from the core .NET Framework?

@CreepyGnome
Copy link

@npehrsson Well the title is "Complex and/or value types" so they are show a clear distinction between the two. Value Type here I would assume means structs (since they already support primitives), and Complex Types would mean every other type of object that doesn't have a primary key (aka entity). However it seems that Complex Type here may mean something more limited in this feature. Since the feature has no description to clarify what its intent is, it will always be vague in what they plan to implement vs what the true definition of those words in C#.

@divega
Copy link
Contributor

divega commented Aug 25, 2015

Value Type here I would assume means structs

@CreepyGnome We didn't mean structs although they could be structs. I think the correct title would be "Complex Types and/or values objects". I can fix that. We punted on the decision on whether we would just support "complex types" in the traditional EF sense or purer DDD-style value objects.

Since the feature has no description to clarify what its intent is

Will fix this as well. @rowanmiller feel free to make edits.

is there another feature in the backlog for support things like Dictionary, Lookup, HashSet, (all collections basically), Money, etc from the core .NET Framework?

I don't think we currently have an issue for rich collection support (I thought we did have something in the backlog but I couldn't find it). It should include mapping to ordered collections as well.

I see this as a separate feature from rich scalar property support. For the latter, providers can support different scalar types if they can handle them natively and we have an item to extend that using conversions at #242.

@divega divega changed the title Complex and/or value types Complex and/or value objects Aug 25, 2015
@divega divega changed the title Complex and/or value objects Complex types and/or value objects Aug 25, 2015
@divega
Copy link
Contributor

divega commented Aug 25, 2015

@CreepyGnome I have created #2919 for rich collection support.

@roji
Copy link
Member

roji commented Oct 23, 2015

Just to add some PostgreSQL perspective here... PG supports user-defined composite types: users can define new database types with arbitrary fields, and then use those types as columns in tables. Npgsql 3.1 (the current dev version) includes first-class support for these at the ADO.NET level by allowing the user to map a CLR type to composite types. It would probably be trivial for the Npgsql EF7 TypeMapper to expose these mappings to EF7, allowing arbitrary objects to be mapped to columns. This would be very similar to mapping an object to a JSON/XML field, except it's much more efficient.

I don't think all this has any bearing on EF7 (totally PostgreSQL- and Npgsql-specific) but it's related.

@rowanmiller
Copy link
Contributor Author

@roji this is great info to have, thanks!

@jkanczler
Copy link

Please, consider to add navigation property to the complex type. For example money is value object (domain driven design). A money has got an amount and a currency, but we are not interested in the id of the money, we just would like to represent 112.5 USD and store that in the database. But the currency is an entity in our model with a primary key. So we should be able to navigate from our money object to the currency.

It should be something like this:
[ComplexType]
public class Money
{
public decimal Amount { get; set; }
public Currency Currency { get; set; }
}

Thanks!

@Gillardo
Copy link

Gillardo commented Jan 7, 2016

Are complex types supported yet? In EF6 you could declare a property as an object, without a Key and it would create the columns in the same table. For example,

public class MainObject() {
    public long Id { get; set; }
    public SubProperty Sub { get; set; }
}

// No key defined here as shouldnt need it
public class SubProperty() {
    public string Text { get; set; }
}

I have tried this in rc1 and i am getting an error the following, but maybe i am not setting something up correctly.

The entity type 'SubProperty' requires a key to be defined.

@rowanmiller
Copy link
Contributor Author

@Gillardo no, this item is on the backlog and will be tackled post 7.0.0

@lucamorelli
Copy link

I have a db context, and I want to add support for tracking the user that added, modified and virtually deleted the record. To to this I added to the class the required properties

public interface ILoggedTable
    {
        int UtenteCreazioneId { get; set; }
        DateTime CreazioneTs{ get; set; }
        Utente UtenteCreazione { get; set; }
        int ?UtenteModificaId { get; set; }
        DateTime ?ModificaTs{ get; set; }
        Utente UtenteModifica { get; set; }
        int? UtenteCancellazioneId { get; set; }
        DateTime ?CancellazioneTs{ get; set; }
        Utente UtenteCancellazione { get; set; }
    }

and this implies that in the user entity I'll have 3 collections of entity has been deleted,added, modfied by the user, for every table. To avoid this I would like to group these navigation properties in a generic class this way:

    public class LoggedTableRevProps<T> where T : class
    {
        public virtual ICollection<T> Creati { get; set; }
        public virtual ICollection<T> Modificati { get; set; }
        public virtual ICollection<T> Cancellati { get; set; }

        public LoggedTableRevProps() {
            Creati = new HashSet<T>();
            Modificati = new HashSet<T>();
            Cancellati = new HashSet<T>();
        }
    }

All seems work fine, but when I try to create the migration I obtain this error message

The expression 'p => p.UtentiLogProps.Creati' is not a valid property expression. The expression should represent a property access: 't => t.MyProperty'.
Nome parametro: propertyAccessExpression

Is this the same problem?

@reneherrero
Copy link

Hi guys,
I've been digging around in the 2.0 preview 2 bits for the ComplexType functionality as described by @ajcvickers but haven't found anything? Has this been pushed back? Any documentation on the topic?
Thanks

@ctolkien
Copy link

ctolkien commented Jul 23, 2017

@reneherrero Complex type / Owned entities s are in 2.0-preview2. See the release notes here for info on how to implement:
https://blogs.msdn.microsoft.com/dotnet/2017/06/28/announcing-ef-core-2-0-preview-2/

@julielerman
Copy link

julielerman commented Jul 23, 2017 via email

@weitzhandler
Copy link
Contributor

weitzhandler commented Aug 19, 2017

  1. Is there a way to define owned entities via attributes?
  2. Are collections supported as owned types too (i.e. Contact.Addresses)?

Looks like mission of complex types has been accomplished. The only thing blocking me from moving to EF Core is now TPT (#2266), sadly it's on the Backlog milestone.

@smitpatel
Copy link
Contributor

@weitzhandler - Currently owned type must be defined by fluent api only. There is no support for attributes. Collection of owned entities is not supported atm. it is being tracked here #8172

@weitzhandler
Copy link
Contributor

weitzhandler commented Aug 20, 2017

@smitpatel
Thanks for your quick response!
I'm glad complex-types made it into 2.0. Would be nice if attributes will be supported out-the-box.

@SneezeWeeze
Copy link

@smitpatel Yes, knowing whether or not complex types via attributes is on the docket or if we should just plan on using Fluent API. Can you respond?

@smitpatel
Copy link
Contributor

@SneezeWeeze attribute support is being tracked at #9487

@crhairr
Copy link

crhairr commented Nov 10, 2017

This should not be closed. Complex type support should not be considered implemented by the "Owned" properties. The mechanism does not support deeply nested types as required by document DBs. The table-splitting mechanism is also a relational concept, and should be pushed down to the relational layer.

@divega
Copy link
Contributor

divega commented Nov 10, 2017

@crhairr this is closed because owned types is a superset of what complex types represented in EF6. Other more specific functionality that we are planning to support will be tracked in new issues.

Re "deeply nested" I wonder what you mean.

@crhairr
Copy link

crhairr commented Nov 10, 2017

Deeply nested:

public class EntityA
{
    [Key]
    public int Id {get;}

    public ComplexType1 OuterComplexType {get;}
}

public class EntityB
{
    [Key]
    public int Id {get;}
}

public class ComplexType1
{
  public ComplexType2 InnerComplexType {get;}
}

public class ComplexType2
{
    public EntityB InnerNavigation {get;}
}

In MongoDB, this creates an object that looks like this:

{
  "id": 1,
  "outerComplexType": {
    "innerComplexType": {
      "innerNavigation": {
        "id": 2
      }
    }
  }
}

This type of structure does not appear to be supported by EFCore, especially the inner navigation off of a nested complex type.

@anpete
Copy link
Contributor

anpete commented Nov 10, 2017

@crhairr That should work. If it doesn't please file an issue with a small repro, thanks!

@crhairr
Copy link

crhairr commented Nov 10, 2017

When I tested it a few weeks ago, it appeared not to work when the "Owned" type is not a valid entity type (ie: does not have Key property). I'll take another look and see if I was doing something wrong.

Also, ownership did not seem to allow sharing a child type between multiple parent entities. For example, sharing an complex Address type between two entity types:

public class Business
{
    [Key]
    public int Id {get;}

    public string Name {get; set;}

    public Address BusinessAddress {get; set;}
}

public class Residence
{
    [Key]
    public int {get;}

    public Address ResidentialAddress {get; set;}
}

public class Address
{
    public string StreetName {get; set;}

    public int StreetNumber {get; set;}

    public City City {get; set;}

    public State State {get; set;}

    public string PostalCode {get; set;}
}

public class City
{
    [Key]
    public int Id {get;}

    public string Name {get; set;}
}

public class State
{
    [Key]
    public int Id {get;}

    public string Name {get; set;}
}

@AndriySvyryd
Copy link
Member

AndriySvyryd commented Nov 10, 2017

@crhairr key properties are not required for owned types and sharing the same CLR type is supported. You need to call .OwnsOne() for each reference to an owned type. Please open a new issue and post your configuration if it still doesn't work for you.

@crhairr
Copy link

crhairr commented Nov 10, 2017

Interesting, I thought I had tried that. Like I said, I'll definitely revisit it.

Also, for context, I'm interested in complex types as part of a MongoDB provider for EF Core that I created. The problems I've seen may be related to how I have to manage and map the metadata for use with the MongoDB C# driver.

Thanks for the quick responses! I'll let you know what I find.

@crhairr
Copy link

crhairr commented Nov 12, 2017

After revisiting, I've found a two issues:

  1. The "Key required" exception I was seeing is because one of the complex type properties in my sample model is enumerable. After removing the enumerable property, the metadata generation works. However, support for enumerable complex type properties is required for MongoDB, so this Ownership is still not a good stand-in.

  2. Ownership does something weird when attempting to write the parent entity to its collection. I haven't fully investigated this yet, but it looks like something is calling Database.SaveChangesAsync with the "owned" entity type, even though these types should be saved as part of their owning entity. This is causing the child entities to be broken up and saved into different MongoDB collections instead of treated as subdocuments and saved in the parent. My guess is that the table-splitting is at the wrong abstraction level and belongs in the relational layer instead of the EFCore project. This will allow document DB providers to write their own translation mechanisms to handle saving owned/complex-type properties.

I'll open different issues for these two points. But I still disagree that this one - RE: actual Complex Types - should be considered closed, especially if the EFCore team is serious about supporting document DB providers.

@smitpatel
Copy link
Contributor

@crhairr

  1. Enumerable of owned entities is not supported yet. See Support collections of owned entities #8172
  2. Table-splitting is in relational layer only. Saving owned entities is much different in core/relational/non-relational database.

For Core, owned entities are just like normal entities with key being borrowed from the owner. It does not need any special processing apart from key propagation and will have its owned collection/table just like any other entity. The idea of owned entity is to allow user to write a complex type and map it without worrying about the setting up PK. But once the domain model is adjusted for lack of PK through owner, everything else will remain as if the owned entity was a normal relationship with explicit PK.

For relational, it does special processing that, owned entities are made part of the same table as owner. That is what table-splitting is. Split the table between 2 different entityTypes. This is somewhat similar to non-relational database. Owned entities must go into parent table only but the main difference is relational databases allow partial updates. Hence you can save owned entities separate from parent. While that is what core already does (saving owned entities separate from parent), relational just follows the suite only by changing the target table to owner's table for table splitting purposes. In summary, Core saved owned entities to different collection separately, whereas relational saves owned entities to same table separately.

For non-relational,
The mapping is also similar to relational. It is not exactly table splitting since non-relational does not have a flattened table concept. Owned entities will be part of its owner document in database. From that point onward it is easy to define how to save changes. If the database supports partial updates, then you save owner on itself and when you are saving owned entity separately, you add another key-value pair for owned entity in the owner document. If the database does not support partial updates, then on provider level, while saving the owner you look for all entities owned by the owner, embed them in the owner document before sending to database so they are saved in one document. And mark those owned entities as saved (or ignore them if you have to process them again).

@DanJ210
Copy link

DanJ210 commented Aug 6, 2018

Looking for this feature as well. Supporting complex types. Or tables without a primary key.

@julielerman
Copy link

julielerman commented Aug 6, 2018

Hey @DanJ210 - the complex type support came with Owned Entity type (https://docs.microsoft.com/en-us/ef/core/modeling/owned-entities) feature in EF COre 2 and the tables without PK came with the QueryType in EF Core 2.1 (https://docs.microsoft.com/en-us/ef/core/modeling/query-types)! So you have arrived at just the right time! :)

@DanJ210
Copy link

DanJ210 commented Aug 7, 2018

@julielerman Oh well cool thank you very much! I actually just used the QueryType and got it working. So great! Thanks!

@arielmoraes
Copy link

I have a situation where I have a Value Object that may be null and inside the VO I have a decimal property, the problem I'm facing is that EF Core 2.1 forces this decimal to be Nullable as it is marked as not required in the entity configuration. What I think is the VO itself should be null if the value does not exist from the user perspective and if the value exists, the VO should not be null and the decimal property should have a value. Is there any way to have a VO with a non-nullable property and the same time mark it as not required?

@AndriySvyryd
Copy link
Member

@arielmoraes this mapping will be enabled by #9005

@arielmoraes
Copy link

arielmoraes commented Aug 30, 2018

Oh no my Domain will have to be bloated with database constraints :(

natemcmaster pushed a commit that referenced this issue Oct 31, 2018
@ajcvickers ajcvickers modified the milestones: 2.0.0-preview2, 2.0.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Projects
None yet
Development

No branches or pull requests