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 https://github.com/aspnet/EntityFramework/issues/3486)
Is there a plan for when this will be implemented?
@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).
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.
@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.
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.
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" [email protected]
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
https://github.com/aspnet/EntityFramework/issues/246#issuecomment-134400942
.
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
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
@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#.
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 https://github.com/aspnet/EntityFramework/issues/242.
@CreepyGnome I have created https://github.com/aspnet/EntityFramework/issues/2919 for rich collection support.
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.
@roji this is great info to have, thanks!
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!
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._
@Gillardo no, this item is on the backlog and will be tackled post 7.0.0
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?
@lucamorelli - It is different issue. Can you file a new issue with your model classes & your DbContext code?
@rowanmiller Complex type is the name of keyless object in OData too.
Complex types are keyless named structured types consisting of a set of properties. These are value types whose instances cannot be referenced outside of their containing entity. Complex types are commonly used as property values in an entity or as parameters to operations.
@smitpatel I created this issue https://github.com/aspnet/EntityFramework/issues/4564 with the link to the sources of the sampe
+1 vote for serialziing a complex type into JSON stored in a single column. We are currently doing it ourselves, but it would be great if it would be supported out of the box by EF7.
I vote against serialization.
How I will include one of the complex type properties into column calculation or into query WHERE condition if the whole complex value would be serialized into one column?
What about indexes? How could I include such columns to them?
Giving developer the choice to serialize or not (by FluentAPI or by Data Annotations) would be the best option I think. But unserialized plain Complex Type option (EF6-style or similar) is a must.
@zhaparoff Of course, it should be a choice. Sometimes there are cases where I never have to query the serialized data and I just want to store it into a column.
@zhaparoff Querying can work very easily for JSON structures: simply search for text matching the pattern: "Property": "Value". This is very similar to logging structured data within logging statements on the back-end (Serilog) and the search ends up being pretty straight-forward.
In addition, JSON give additional benefits over traditional column-based mapping. For example you can include small arrays or nested structures, so if you have a person's phone numbers or their email addresses, you don't need to create separate tables for Phone Number, Email, Address etc.
While I agree with you giving developers the choice of how to serialize would probably be best, recently our team has been realizing JSON serialization has a lot of benefits for complex types – things that are essentially value types and you don't need to have references for (ie: referential integrity). There's a big parallel here to value types / structs. JSON serialization allows you to achieve the same features as a struct, essentially not limiting you in either nesting nor the types you can include in them (arrays, dictionaries, sub-objects). Column mapping does not have these benefits.
So if we're gonna have only ONE of these, I vote for JSON all the way. :)
@marchy
simply search for text matching the pattern: "Property": "Value".
I'm afraid the performance penalty could be rather painful for some scenarios in this case.
For example something like WHERE Address.Apartment = @Apartment
for table with 2M rows with Address containing a few kilobytes of data.
I think complex type flattering concept shouldn't be mixed with the NoSQL one (which benefits you've described). Both of them are very nice to have, but trying to replace one by another is a bad idea.
@marchy: Sorry, but this is non-sense. If you're in need of queryable "json documents", use a document database (which Entityframework Core will eventually officially offer provider support some time in future) and serialize/deserialize the whole model into it. That's what they are and what they are good at.
Imagine the performance penalty if you try to deserialize/parse every json of all database rows trying to match a value. It's not a simple "property":"Value"
string search, you'd also have to consider nested objects and arrays (both of values and of objects).
There is absolutely no reason to add json seralization to a single column. if you need it, you can implement it yourself for your applicaton.
@TsengSR The point is not to go overboard with value types, but rather to support use cases which EF6's column-mapped complex types do not.
I gave the example of a users's phone numbers or emails as some great candidates for serializing out to a single column. Our structure for phone numbers on our Contact entity for example is:
[
{
"CountryCode": "CA"
"CanonicalNumber": "+12223334444"
"LocalNumber": "(222) 333-4444"
"PhoneKind": "Mobile"
},
{ // second phone number
....
}
]
Note how PhoneNumbers are not only complex types but there's also an array of them since the user could have multiple ones on their account.
There's no reason to create separate PhoneNumbers/Emails/SocialNetworks/Addresses etc. tables in the database nor does this warrant a switch to a document database. Doc DBs have other strengths when you have deep document structures but scenarios like these are not the place for them.
We've been doing regular column-mapped for years @TsengSR and I am highly familiar with them. In practice though they are limited and do not always provide the best option. Being able to use JSON mini-structures mixed within traditional relational databases could be a very welcome mix that the general .NET developer community should get familiarized with – and I think you'll find that we will increasingly find out how to get the best of both DB worlds as opposed to polarizing to one or the other.
I would love to see Entity Framework be at the forefront of thought leadership on this front as opposed to behind on the catch-up curve.
@marchy
I've created a test to compare query performance https://github.com/zhaparoff/FlattenedSerializedTest
For test tables with 100k rows it gives:
Average was taken from 10 test runs on localDB (SQL 2014) located on SSD drive.
Querying JSON column is 150 times slower!
Even if LIKE
operator will be used instead of equality for flattened query, although it is meaningless, querying JSON would be more than 10 times slower anyway.
I have no SQL 2016 to test JSON_VALUE or JSON_QUERY functions, possibly, I could try to test them tomorrow. But I don't think it would change results noticeably.
@zhaparoff Nice work Anton!
That would be a good piece of guidance on this, that if you need to query on the complex types you should prefer storing them as columns. If it's more just data that comes back with your core entity all the time then the performance is not an issue.
One note on your tests though, you are using single columns and repeating them explicitly a limited number of times (ie: PhoneNumber3) – as opposed to having related phone number tables that point back to the original entity. These are all design decisions in a system so I don't mean to scrutinize, but even if you limit the system to have say 5 numbers that would be 20 columns for the phone number data alone. Alternatively storing them in a PhoneNumbers / Addresses etc. tables would mean you would have to do additional joins for your search. I wonder what the performance difference would be truly like in that scenario. I imagine a lot less pronounced than 150:1.
Being able to support value objects is a must for me and the project I'm planning on using ASP.NET Core for. I hope this makes it into RTM and I stop seeing this:
The entity type 'MyApp.Model.Price' requires a key to be defined.
Gave NogginBox a +1 but I know that the reality is the RTM is just not targeted to big enterprise apps which is where I would feel the most pain re not having value objects. If you are not targeting cross-platform and can use EF6, you _can_ use ASP.NET Core (for other benefits besides xplat) with EF6. https://msdn.microsoft.com/magazine/mt632269
I can't see many people being very happy about this feature being left out of EF7 initial release especially as we had it in EF6. I completely disagree with @julielerman that this will be missed by mainly "large enterprise apps". This is a very fundamental feature for an ORM. Are you telling me that only large enterprise apps need to store addresses, or semantic versions, or ...? I know you guys only have a finite amount of development time, but really we shouldn't be going backwards with new releases.
@NameOfTheDragon, @julielerman I didn't use Value Objects in my first few EF projects because I didn't know what they were. I don't write enterprise apps, but now I know what value objects are I find them incredibly useful and would find it hard to write a project without wanting to use them.
@NameOfTheDragon Though I feel your pain it has been explicitly said that EF7 is not an 'upgrade' of EF6 but it is a complete rewrite and something entirely different (hence it will be named EF Core 1.0 from now on). As long as EF7 (or EF Core) is not as feature complete compared to EF6, the team has stated that they aren't recommending it as the version to use. Hence you cannot expect everything that was in EF6 being present in EF Core upon release. So, all in good time :-)
Guys, if you're talking about the Value Object DDD pattern, that scenario will just work. Value objects are allowed to be EF entities with their own table. What makes them value objects in the domain rather than entities in the domain is how you treat them, not how EF treats or stores them.
If you're talking about wanting to group together properties in the same table into a structured type, that's what this ticket is about. The workaround would be to move the properties into the containing class for now. To me that has almost zero impact on the architecture of an app. It's an easy refactor in either direction and it doesn't impact how you reason about your domain. Alternatively, you can map private EF properties in the containing type which read and write the complex type's properties.
It's syntactic sugar which I am still very much looking forward to. It would be completely awesome to be able to use struct types for complex types (EF6 never supported this).
@razzemans is exactly correct. EF Core is not a replacement of EF6 and does not supersede it. It will get there eventually. It's better to release early what they have than keep the project private until 2018. I am stoked that the team is putting so much effort into getting EF right.
@jnm2 value objects will only work in EF Core if you give them an ID, which to my (pedantic) understanding stops them being value objects.
For example when they have an ID it would be possible to use the same address entity for the delivery address on a order and the users default address, which might not be what you wanted and could mean that you changed the address for an old order when the user updates their default address. You can get around this with code, but a pure value object with no ID stops this being possible.
It also creates the need to do more joins, which can be an issue if you get over excited about your use of value objects.
My main concern about going that route, would be that I would want to migrate them back into the same table when this feature becomes available in later versions.
I'm not annoyed about the lack of this feature although I would have really liked it to be in RTM. It does mean that I probably won't be using EF Core 1.0 though. I'm mainly commenting on this issue in the hope that it bumps it up the schedule for the next release and I get to use it sooner rather than later.
@NogginBox It stops them from being EF complex types, but it doesn't stop them from being DDD value objects. DDD is just unaware of the ID. It's common to put DDD value objects in their own table which makes them EF entities but not DDD entities. EF requires a primary key on every table, which DDD doesn't see and doesn't care one way or the other about. Whether a DDD value object is an EF complex type or an EF entity is purely a persistence concern- a DDD tenet is that the domain is unaware of persistence.
IIRC EF6 doesn't support value types, only classes, so you were already having to ward off the potential for sharing a reference at the C# object level and mutating multiple entities inadvertently. (Which is why I'm looking forward to using value types which are inherently copied on read/write.) This would be the same, only you'd have to make your copies explicit and the copy would not copy the ID.
The joins concern is good. The workaround for that is to move the properties into the parent type or to add private properties for EF to use that act as proxies to the complex type's properties.
I too would have liked to see it. However, because I refused to weaken my domain model with EF6-compatible constructors, setters, collections and primitive types, I've been mapping domain models to data models. That means that I have the purest forms of domain modeling (yay for immutable structs and readonly collections!) but if moving to EF7 means my data models change, I don't care. A few lines of mapping code changes and I'm set to use the new performance and new APIs and new data stores.
Basically my data model demonstrates what I want my tables to look like and my domain model is my domain model. When EF's object mapping catches up one day, I'll be able to get rid of the data model.
@jnm2 structs would be even better. I have been using objects as pseudo value objects and although I try not to share them I like to know that when it gets persisted all potential identity is not saved.
So to simplify:
Simple example code would of been great @jnm2 :)
@jnm2 I've never considered using structs in this way and did not know you could save private properties. Is there any guidance or examples on this?
http://romiller.com/2012/10/01/mapping-to-private-properties-with-code-first/
I'm sure Google will turn up many others. it's a newer EF6 feature. I used this:
``` c#
public class DetectPrivatePropertiesWithColumnAttribute : Convention
{
public DetectPrivatePropertiesWithColumnAttribute()
{
Types().Configure(config =>
{
foreach (var property in config.ClrType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance))
if (property.GetCustomAttributes(typeof(ColumnAttribute), true).Length != 0)
config.Property(property);
});
}
}
And `DbModelBuilder.Conventions.Add<DetectPrivatePropertiesWithColumnAttribute>();` in your `DbContext`'s `OnModelCreating`.
And then in your models:
``` c#
public StructType StructProperty { get; set; }
[Column("StructProperty_A")]
private string StructPropertyA
{
get { return StructProperty.A; }
set
{
var structValue = StructProperty;
structValue.A = value;
StructProperty = structValue;
}
}
I mainly used it for this:
``` c#
[NotMapped]
public PositiveInteger Number { get; set; } // Saves a ton of if (value <= 0) throw new ArgumentOutOfRangeException...
[Column("Number"), DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int NumberPrimitive { get { return Number; } set { Number = (PositiveInteger)value; } }
```
Until I finally moved to a separate data model.
Don't get me wrong... I love value objects. I'm just not considering efcore for any serious work yet so I am not going to stress out about not using them. I find myself designing my domain with them out of habit then having to undo. And if you are set on efcore, then +++ to @jnm2 's point. I map from domain to EF's data model (the in-memory model that EF infers at runtime) using EF's mapping when it's easy and I don't have to make annoying (or worse) concessions. Otherwise it is time for a mapper between domain and data model defined by separate classes + EF DBContext. So EF mapping layer is my default mapper when using EF. But sometimes it is just not sufficient and I go to (or recommend) the effort of building a separate data model. Your choice. Pick your battles.
Another point is that Jimmy Bogard doesn't even think the ef6 complex types do enough to map types that you've defined as value objects. So he's been either just using one to one or going the extra mapper route depending on the situation. Gogglebing Jimmy Bogard, something like "what's missing in ef6 for DDD" to read more. And then there's that collection conundrum, too as well as the problem of mapping private fields. So if you are okay without those in EF6, maybe support for value objects isn't such a huge deal except for the problem of it being "taken away" temporarily.
I'm glad folks are trying out EF Core. It does give good feedback and stats about which features will be priorities after 1.0 like @NogginBox said. I've already rewritten everything against EF Core even though we're staying with EF6 for production, just to see what we will be blocked on and to give feedback early.
Yes, Rowan has some great solutions to problems. Unfortunately I haven't had enough coffee yet to remember my conversation (too busy trying to type all this on the iPad) with him about its limitations. Maybe it was just about the fact that it does do props, just not collections. Also that it's a workaround. Fine for me. Sadly, so many devs push back on workarounds vs built in and then there's the "it's IMPURE" nonsense argument, ;)
I like that plan of pushing everything to efcore to see where your own code is limited,
@julielerman I would love to have had (and still would love) an article that thoroughly addresses that question: weighing the pros and cons of staying within EF modeling constraints or using a data model and mapping yourself. When to consider making the switch. And what that means for creating a rich, disciplined model that doesn't become anemic. I feel like I've wasted a lot of time not having a fundamental understanding of this from the beginning.
Hey, working with 'impure' code will always make me feel dirty inside. But that ship sailed long ago. :-D
Perhaps I will copy and paste what I wrote into my blog ;)
You should!
@jnm2 done and now will be away from computer for hours: http://thedatafarm.com/data-access/icymi-my-general-advice-re-ddd-ef-domain-models-with-or-without-data-models/
Hi,
I have been trying to work around the issue with the missing complex types in EF Core by using the private proxy-property approach.
I added properties to my domain objects like
[ComplexTypeProxyProperty]
private double Gesamtmenge_Betrag
{
get { return Gesamtmenge.Betrag; }
set { Gesamtmenge.SetPrivate("Betrag" , value); }
}
To avoid adding a reference to EF to my Domain Project, I created a custom ComplexTypeProxyPropertyAttribute class to flag the properties. Because the properties in the value objects have private Setters I created a SetPrivate Extension method that sets them via reflection.
In my EF-Project I can find the properties with
public static IEnumerable<PropertyInfo> DiscoverComplexTypeProxyProperties(this Type t)
{
foreach (var property in t.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance))
if (property.GetCustomAttributes(typeof(ComplexTypeProxyPropertyAttribute), true).Count() != 0)
yield return property;
}
This is Close to what @jnm2 suggested, but I did not find a way in EF Core to make it work as a convention. To Register the properties with the modelBuilder I created an Extension:
public static void MapComplexTypeProxyProperties<T>(this EntityTypeBuilder<T> typeBuilder) where T : class
{
var properties = typeof(T).DiscoverComplexTypeProxyProperties();
foreach (var property in properties)
{
typeBuilder.Property(property.PropertyType, property.Name).HasColumnName(property.Name);
}
}
In OnModelCreating I exclude the value object properties and add the private proxies:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Schüttung>()
.ToTable("Schuettungen")
.Ignore(s => s.Bierfarbe)
.Ignore(s => s.Gesamtmenge)
.MapComplexTypeProxyProperties();
base.OnModelCreating(modelBuilder);
}
When creating the database the table structure looks fine. During runtime the Proxy properties Show the correct values. But on SaveChanges the values of the Proxy fields are not written to the database.
I am not sure if this is the right place for the question, but I feel that I am Close, but waht am I missing?
I would like to underline the importance of the post of @jkanczler
It is a crucial and from my point of view unnecessary lack of EF6 to disallow the use of navigation properties inside of complex types. I would go even further - complex types are useless without the possibility to place navigation properties inside.
Let's take to common example of address: if you want to reference a country entity.
Hopefully EF Core is concerned about this.
Thanks for any attention !
Yours, Fabianus
@rowanmiller @jkanczler @fabianus76 The ability to have reference navigation properties in complex types was never in question, was it?
@trichling I'm willing to bet that SetPrivate
doesn't work. Did you test it? I can already see that dotting into Gesamtmenge
to set a field is not going to work because after you set a field of a value type, you have to set the resulting entire value type back into Gesamtmenge
. Also, setting a value-typed this
via reflection isn't going to have any effect because you're mutating a boxed copy of this
.
It's confusing, I know. I would strongly discourage mutating value types and reflection and encourage plain old C# coding. It's a tiny bit more typing but it's more honest and transparent and safer and faster, and you can reuse the With*
methods other places in your code: gist
Hello @jnm2 , glad to hear that.
What I am sure is that in EF6 navigation properties are NOT supported in complex types - which is a major misconception in my point of view.
jute one reference :
http://stackoverflow.com/questions/1614703/how-do-i-add-a-navigation-property-for-a-entity-framework-complex-type
If the team has a diffrent ponit of view - please let me know and I'll give good reasons ...
Thanks, Fabianus
@fabianus76 I thought they were in EF6. Never mind me then.
@rowanmiller Since complex types are just a way to group related properties on an entity, it makes total sense for there to be both reference and collection navigation properties in the complex type. Conceptually they become navigation properties on the entity class.
Hi @jnm2,
Initially I used structs for the value objects, but tried classes later. It was that model I tested SetPrivate
on, which works well on classes (gist). Furthermore the properties need to have at least a private setter - only getter does not work. I was already willing to take a lot of compromise to make it working ;-)
But I will definetly give the With*
-approach a try, thanks for the suggestion!
@jnm2 @fabianus76 - You are correct that navigation properties are not supported in complex types in EF6. We haven't designed this feature yet for EF Core, but I see no reason that we would continue to have that same limitation in EF Core.
@rowanmiller - thanks for this feedback !
@jkanczler - isn't that something ? This choice of previous EF is such a nonsens. But now it'll be healed.
Best regards,
Fabianus
I was about to tackle PostgreSQL composite type support in Npgsql's EFCore provider (see previous comment), and came back to this thread.
I guess I just wanted to reiterate the importance of allowing multiple mapping strategies which the user can choose from, including strategies that are provider-specific. For example:
Different strategies may be necessary for the same model with different providers - map to a PostgreSQL composite when using PostgreSQL, or to a string column with Sqlite. Should be similar to ForSqlServerToTable
type builder extensions which already exist.
FYI I'll be delaying composite type support in the Npgsql EFCore provider (https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/22) until there's some more clarity here to avoid going in the wrong direction.
We will discuss complex types in an upcoming design meeting. Here are some notes to drive that discussion. All of this is subject to change and is only a starting point from which the design will evolve.
Complex types
The feature request for complex types (EF6 terminology) or value objects (DDD terminology) can mean different things to different people. As a starting point, let's define a complex type as such:
A complex type collects properties from one or more types into a new type, which is then referenced from the containing types. The new type does not have its own identity. The properties of the new type are treated by EF in essentially the same was as properties of the containing type.
JSON, etc.
Closely related to complex types is the ability to serialize property values to and from JSON, XML, or some other format stored in the database. For JSON, this is tracked by issue #4021. Using this kind of translation or any other JSON/XML support does not inherently make a type a complex type and so is largely orthogonal to the discussion of complex types.
Also related to this is the ability to map multiple properties to a single database column, perhaps serializing multiple properties into a single JSON type in the database. This again does not inherently make that collection of properties a complex type.
Collections of scalar types
Collections of simple types (int, string, etc.) is not inherently part of complex type support. This is tracked by issue #4179.
Structs
Complex types can be .NET value types--i.e. C# structs. It is largely unimportant to EF whether a complex type is a class or a struct because complex types do not have identity, and hence there is no guarantee of or attempt at identity resolution for complex types. However, it does have an impact on how changes are tracked--see below.
Mapping and facets
In the simplest case, mapping of the properties of the complex type is handled just as if they were properties of the containing entity type. However, there will be some differences, such as in the convention for creation of column names, which can use the complex type name or referencing property name to disambiguate column names.
Fluent API will be based on EF6. For example:
``` C#
modelBuilder.ComplexType
.Property(t => t.Location)
.HasMaxLength(20);
The same changes made for entity types in EF Core--e.g. string-based API--will also be made to the ComplexType API.
The model should allow configuration of property facets on the complex type definition, as shown above. These will apply to all uses of the complex type. However, facets can be overridden on each use of a complex type inside a class definition. The code above applies a max length of 20 to all uses of the CourseDetails.Location property. To set facets for just the use of the complex type in a given entity type, use the dot notation to configure the property:
``` C#
modelBuilder.Entity<OnsiteCourse>()
.Property(t => t.Details.Location)
.HasMaxLength(20);
This code sets the max length of the location property when it is referenced from the OnsiteCourse entity through the Details property.
Nullability
Setting an reference to a complex type to null is treated the same as setting all the properties to null. If the complex type contains any non-nullable properties, then these properties are treated as if they are set to the CLR default.
The default behavior when querying is to always create an instance of a complex type, even if all its properties are null. However this can be configured with metadata on the complex type:
``` C#
modelBuilder.ComplexType
.ConstructNullObjects(false);
This means that if all properties of the complex type are null when queried from the database, then the reference to the complex type will be set to null instead of creating a new instance. If any properties are non-nullable, then a new instance will always be created.
For C# structs, a new instance will always be created.
**Navigation properties**
Properties of a complex type can act as the dependent end of a relationship. That is, a complex type can contain FKs and reference navigation properties pointing to a principal entity type.
At this time, complex types cannot act as the principal end of a relationship since this requires that the complex type either borrow the identity of the containing entity type or have its own inherent identity, both of which are problematic.
It is probably also good to disallow inverse navigations pointing back to the complex type from the principal end, since while technically possible they would likely be confusing.
**Query**
Query can use the properties of the compelx type just as it can use any other property of the entity type.
**Nesting**
A complex type can contain other nested complex types.
**Keys**
Complex types can contain properties that are part of the entity's keys. This is because properties of a complex type behave just like properties of the containing type.
**Sharing instances**
Instances may be shared. Changing some property of a shared instance will result in changes to all places where the instance is tracked.
**Mutability and change tracking**
It may be beneficial for applications to treat instances of complex types as immutable, but EF will not require this. You can tell EF to treat the type as immutable, which will then affect how change tracking is performed.
``` C#
modelBuilder.ComplexType<CourseDetails>()
.IsMutable(false);
If the complex type is mutable (the default), then change tracking works like this:
If the complex type is marked as immutable, then:
Note for EF team: you may want to read through this before the design meeting discussion.
@divega @rowanmiller @bricelam @anpete @AndriySvyryd @smitpatel @lajones @maumar
This looks like it will be solid and fantastic. For users of EF, I would recommend using immutable structs because it's dramatically less to go wrong and the language enforces value semantics on you, so you work with it the way you should be thinking about it.
One thing that surprised me is that you will allow entities to share references to mutable complex types. If that ever happened in my code, I'd want EF to complain loudly. What's a good use case for that? What happens when you load data into two entities that are sharing a complex type instance, or one entity with two properties pointing to the same complex type instance?
For those that go the class route, can complex types inherit from other complex types? What about inheriting from an entity type?
For the superior design with structs, you'd use composition (nesting). I assume facets of properties on nested complex types (whether struct or class) can be overridden on the level of the containing complex type as well as at the entity level, just like you'd have with overriding facets on inherited class properties?
Lastly, it's worth clarifying that DDD value objects can be _either_ EF entities (in which case the persistence-ignorant DDD logic ignores any key) _or_ EF complex types.
Some people do this because they prefer to persist select DDD value objects in their own table even though conceptually they act just as though they are in the same table. It's a persistence concern that doesn't impact the DDD usage at all.
Oh, one more question. With mutable complex class types, will you allow getter-only complex properties, making the complex class's reference readonly but its properties writable?
I just want to throw out there that I am very excited about this being brought up in upcoming design meetings. Especially after reading through the notes that will be driving your discussions. That is all.
So is ComplexTypes/ValueObjects available for the latest EF core version? When I tried to type [ComplexType] it did not show any error message such as 'ComplexType doesnt exist', however I doubt this annotation is working right now.
I wonder, what is the workaround to map a composite property from a domain model/entity to database. Lets say I want to map property 'User.Credential.Email' to the column name 'email', how do I make this with EF core if it does not support complex types. Will the code below work?
modelBuilder.Entity<User>().Property(u => u.Credential.Email).HasColumnName("email");
@HallofFamer I wish it did, but unfortunately that code won't work. You'll get an error message:
The expression 'u => u.Credential.Email' is not a valid property expression. The expression should represent a property access: 't => t.MyProperty'.
@rbeauchamp
So right now I cannot even manually map a composite property to a column with entity framework core with the above approach? If so, how can I do this? This kind of value objects composition is common in DDD.
@HallofFamer: Until implemented only way to do is, is a 1:1 relationship with it's own table. You can use shadow properties, so you don't have to declare a unique identifier on your "complex model".
Something like
modelBuilder.Entity<Customer>()
.HasOne(c => c.Address)
.WithOne()
.IsRequired()
// use shadow property, which only exists in the database, but not on the Address model
.HasForeignKey(typeof(Address), "customerID")
// alternatively also declare/set the name of the principal column on the Customer table
.HasPrincipalKey(typeof(Customer), "addressID");
This way you don't have to declare "CustomerID" on your address or "Customer" Navigation Property on your Customer class. Don't forget, with this approach you'll need to use .Include<Customer>(c => c.Address)
when doing queries, in order to also load this entity as lazy loading isn't implemented
@TsengSR
Thanks for your response, but the above approach is tedious and cannot be applied to value objects in general. I was wondering if someone made extension methods for EF core that allows complex types, or it cannot be done this way. If there's no way to do it right now, can we count on value objects/complex types to become available in next release or at most within a year. If it will take a long time, I'll probably switch to EF 6 for now and wait till EF core truly matures to upgrade.
@HallofFamer:
I don't see a reason why the approach wouldn't work. From outside, the code behaves same as with complex objects. When you assign a new address in the example above, the old gets deleted (due to 1:1 relationship) and the new one gets inserted and addressID / customerID columns get updated accordingly in the database.
And when you change a value within it, it just updates the entity w/o creating a new one.
It's not much more tedious than writing Mappings for DDD too. For a clean DDD approach, your have to map your entities via Fluent-API, otherwise you leak persistence knowledge into your domain (i.e. having to add ID properties, just because it's a requirement for the ORM Framework but has no meaning or value for the domain, like a position in an order doesn't need an id, just a position number. ID for relationship is a pure relation database concept).
@TsengSR
The problem is that, most of the value objects will not be in their own tables. If so, I will need a lot of join queries for each domain model, it is not feasible for any reason. And if there really is no extension for EF core to achieve value objects/complex types for now, I will downgrade to EF 6 and wait till EF core adds this feature.
@HallofFamer If you want same-table struct-based value types and don't mind workarounds for the time being, take a look at my earlier comment and the following code example.
This point is sadly blocking us for using EF Core.
In fact, we've transpose all our valueobject properties into the parent object, to allow EF to create only one table (in a 1-1 relationship), but actually, EF generates shadow properties cause it doesn't recognize that it's a nested object. We already have overloaded in our repository insertion and selection for those shadow propreties (it's really slow (6 more seconds for 175 objects ...), but we haven't seen yet how to overload EF query generator to manage our value objects.
First question : is there a way to achieve this and not slowing down querying ?
Second question : @rowanmiller is this actually planned for 1.2 or after ?
@cdie If you want same-table struct-based value types and don't mind workarounds for the time being, take a look at my earlier comment and the following code example.
@jnm2 Thanks for the tip, however, we cannot use it cause it'll force us to redesign all our domain to fit it as a workaround.
We'll continue to us our custom SQLite DAL in the mean time
So Visual Studio 2017 RC was released and even got an update just a few hours ago, and this feature has yet to be implemented in EF Core. Very disappointed, if it is not included in .NET Core 2.0 update in Spring 2017 I am done with any hopes I have had with EF Core.
The feature is still flagged as being on the backlog. Doesn't look like it will make 1.2 in Q1 2017 so perhaps in the following release in mid 2017?
I run today into that BUG! 2,5 years now NOT listening to the customer...
Moderator warning: @bastienJS Please only post constructive comments
@bastienJS Please mind your language on the Internet
Indeed, this is a very basic feature for Domain Driven Design and for any applications that have rich domain models. If you have Anemic Domain Models that are just plainly collections of getters/setters, you may not need Complex types, but then you are following an anti-pattern that will come back and haunt you in future. Complex types need to be in EF Core asap, its really more important than many of you thought.
Just wait a little more for it, the release cycles of EF Core are much faster than it was the case with former EF versions. We already got mapping to backing fields, which is imho more valuable for applying DDD with EF Core than complex types are.
For complex type there are at least workarounds (treating it as entity for example), but in EF 6 there was no way to map i.e. a collection to a backing field, w/o breaking encapsulation (and weakening) of your domain entity/aggregate root. This is was a real deal breaker for DDD with EntityFramework in the past.
So if my interpretation is correct, Complex Types will be available in EF Core 2.0 to be released in 2018, right?
@HallofFamer Heh probably something like that. I wouldn't hold my breath for 1.x / pre-summer that's for sure. There's no timelines yet for 2.0 yet but given the release cycle of EF / ORMs, early 2018 may be as early as we can hope to get.
It's also to note that there's a few threads here about providing some more holistic solutions (ie: JSON mapping, which is even more direly needed than complex types) which the team is looking at doing in unison. So you can map a complex type to either multiple columns or a JSON-encoded column / BLOB. I personally would much rather see this done right and support more scenarios than EF6 did. We are past the age of relational-only data and JSON in DBs is a huge reality. Thus let's hope the team is delaying for good reasons and that we will all be thankful for it when they do deliver it properly.
The common complex type scenarios should now be possible with owned types and table splitting:
0955e95add77d2b78f3e5a6f68cdce0fd5a18561
95d7af5da028ca4d9af2761df7883ec363a5044e
67d2f2e3b7a23d7ff89e9284b09582c2d2598cde
51b07baaa090a3de86694b7b7b66148b167cb2a9
e79766a89275530fe4e5d7133e1d7927ca8d9e81
80169e6f34134e3d2a33934628fffbfc83b959a2
e6f0e1921216e46de774d8b55785223617982d3d
f5af64f38dc55cb857a5598765c2eb0678ae62a9
644dec8482805ef4ebf2d6faf4d05a25294bb574
e363c3ce454093b0a5fa4447b077a06ccd4e28ff
This is exciting news!
This is exciting. Is this available in a pre-release nuget package, or do we need to wait a little longer?
Yes, I'm wondering the same thing. Currently, I've had to use the System.Data.SqlClient method to execute a stored procedure and use some reflection map its output to a POCO class manually (Since the output doesn't tie to any table entity whatsoever). I'd LOVE to be able to run a command that can do all of this for me
Owned types will be in preview1, basically this allows to map the same CLR type to different entity types/tables. Usually the primary key will be in shadow-state (not present on the entity object) to allow identifying relationships that have incompatible principal keys. Inheritance and one-to-many relationships are not supported yet.
Table splitting will be in the next pre-release. This is pretty much the same as in EF6 and will work with any entity type, including owned types as long as the primary keys are compatible.
We are looking for feedback with scenarios that aren't covered by the above so we can properly prioritize the missing features.
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
@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/
Adding to Chad's comment, they are called "owned entities" and are expressed in fluent API via the OwnsOne method. They're working really nicely! :)
On Jul 23, 2017, at 6:52 PM, Chad Tolkien <[email protected]notifications@github.com> wrote:
@ReneHerrerohttps://github.com/reneherrero Complex types are in 2.0-preview2
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/aspnet/EntityFramework/issues/246#issuecomment-317288037, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AExnEM-KWPRkzLbar0YYvqMA34TB6v-oks5sQ87EgaJpZM4B9geQ.
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.
@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 https://github.com/aspnet/EntityFrameworkCore/issues/8172
@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.
@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?
@sneezeweeze attribute support is being tracked at #9487
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.
@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.
Deeply nested:
```C#
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:
```json
{
"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.
@crhairr That should work. If it doesn't please file an issue with a small repro, thanks!
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:
```C#
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;}
}
```
@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.
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.
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.
@crhairr
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).
Looking for this feature as well. Supporting complex types. Or tables without a primary key.
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! :)
@julielerman Oh well cool thank you very much! I actually just used the QueryType and got it working. So great! Thanks!
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?
@arielmoraes this mapping will be enabled by https://github.com/aspnet/EntityFrameworkCore/issues/9005
Oh no my Domain will have to be bloated with database constraints :(
Most helpful comment
The common complex type scenarios should now be possible with owned types and table splitting:
0955e95add77d2b78f3e5a6f68cdce0fd5a18561
95d7af5da028ca4d9af2761df7883ec363a5044e
67d2f2e3b7a23d7ff89e9284b09582c2d2598cde
51b07baaa090a3de86694b7b7b66148b167cb2a9
e79766a89275530fe4e5d7133e1d7927ca8d9e81
80169e6f34134e3d2a33934628fffbfc83b959a2
e6f0e1921216e46de774d8b55785223617982d3d
f5af64f38dc55cb857a5598765c2eb0678ae62a9
644dec8482805ef4ebf2d6faf4d05a25294bb574
e363c3ce454093b0a5fa4447b077a06ccd4e28ff