EF Core 8 Finally Fixes Value Objects

Ғылым және технология

☄️ Master the Modular Monolith Architecture: bit.ly/3SXlzSt
📌 Accelerate your Clean Architecture skills: bit.ly/3PupkOJ
🚀 Support me on Patreon to access the source code: / milanjovanovic
EF Core 8 is coming out soon, and it has an excellent feature inside - complex types. This is intended to fix the use of value objects with EF Core. You no longer need to use owned types to represent value objects. I'll show you how to do this with EF 8 and the new way to implement value objects.
EF Core 8 RC1: Complex types as value objects:
- devblogs.microsoft.com/dotnet...
Join my weekly .NET newsletter:
- www.milanjovanovic.tech
Read my Blog here:
- www.milanjovanovic.tech/blog
Chapters
0:00 What is a Value Object?
1:01 Configuring Value Objects as Owned Types
2:17 Using Complex Types to define Value Objects
3:51 Demo: Using Value Objects as Complex Types
8:38 Querying Complex Types with EF 8
10:57 One thing that doesn't work with Complex Types

Пікірлер: 121

  • @MilanJovanovicTech
    @MilanJovanovicTech9 ай бұрын

    If you want to accelerate your .NET and software architecture skills, consider joining The .NET Weekly - my newsletter with 29k+ engineers. Subscribe here → www.milanjovanovic.tech

  • @Dpaz2009

    @Dpaz2009

    8 ай бұрын

    Thank you!

  • @kumailn7662

    @kumailn7662

    6 ай бұрын

    why programming with C# is becoming complex. !!

  • @gianlucalocri
    @gianlucalocri9 ай бұрын

    Finally!!! 🤩 Thanks Milan!

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Sure thing :)

  • @EzequielRegaldo
    @EzequielRegaldo9 ай бұрын

    Its AWESOME ! thank you so much for your content

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Glad you enjoy it!

  • @vasiliylu8054
    @vasiliylu80549 ай бұрын

    Thanks! It's very cool feature

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    You're welcome :)

  • @antonmartyniuk
    @antonmartyniuk9 ай бұрын

    I like this feature much, hope collections will be supported too until EF 8 release

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    I don't think we get that in EF 8 :/

  • @JordiC354
    @JordiC3545 ай бұрын

    Hi Milan, do you achieve that complex property works with typed ID, like BookId(Guid ID)?

  • @MilanJovanovicTech

    @MilanJovanovicTech

    5 ай бұрын

    Does it not work for you?

  • @JordiC354

    @JordiC354

    5 ай бұрын

    @@MilanJovanovicTech Not for primary key. Does it work for you?

  • @silvertek
    @silvertek9 ай бұрын

    Will this avoid the exception when using stringly typed ids since we use them as both value/nonentity types for the aggregate but as entity types when we reference them from another aggregate?

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Give it a try? 😁

  • @matthewrossee

    @matthewrossee

    9 ай бұрын

    You mean the identity paradox presented by Amichai Mantinband on his channel? I'm curious as well. Have you tried it yet?

  • @_IGORzysko
    @_IGORzysko9 ай бұрын

    Thanks for the video Milan! The possibility o fetching only value object data from the table is really great 🔥 Are EF 8 value objects tracked the same as "entity" entities? 🤔

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Yes, they're tracked by EF

  • @joebyrne7343
    @joebyrne73439 ай бұрын

    Must the columns be author_? Can this be implemented in db first scenario where the existing columns may not follow that naming convention?

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    You, configure with ComplexProperty and define column with HasColumnName("your_existing_db_col")

  • @tonystoynev7969
    @tonystoynev79699 ай бұрын

    Hey, another great video! But I am not getting the point of having a collection of complex types inside the entity? How this collection will be mapped into the database?

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Could be all mapped to one column as JSON

  • @ArcaneEye

    @ArcaneEye

    6 ай бұрын

    ​@@MilanJovanovicTechcan't you already do that with hasconversion? And wouldn't it be faster to query a relational table than having the SQL server do string magic to find your query target?

  • @aerostorm_

    @aerostorm_

    3 ай бұрын

    ​@@ArcaneEye to answer your somewhat older question, this is essentially a built-in HasConversion json implementation. Document databases are supported by EF now and this paradigm makes more sense if you are using EF to abstract a document DB. If you are abstracting a SQL DB then this feature is not as optimal as querying with relations.

  • @MikyShooter
    @MikyShooter9 ай бұрын

    For all that says this example does not suit the feature, you may be right. It doesn't metter but the explication, that was imo exaustive. Here is another simple example: In case of an order we may have a shipping address related to it. It's not ideal to save the Id of the customer address but the information itself at time t. This because the address could potentially be removed from the customer entity, or even modified. Best thing is to store it separately, as this case, in a complex object, also to sepate concerns in class. Thank you Milan for all your videos.

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Very good example with order + shipping address ✅

  • @jeroen7362

    @jeroen7362

    9 ай бұрын

    The order with shipping addres as mentioned here could be a scenario. Still i would not use it for that. Just add a few fields to the order for the address, postal code and town, country and done. probably country would be a foreign key to the country table. The actual up to date address would be stored in a address table that is referenced by the customer class. This is the address you would show for next checkout and in their profile.

  • @MikyShooter

    @MikyShooter

    9 ай бұрын

    @@jeroen7362 With complex objects, as explained by Milan and by the docs, are still created in the same table. No need to add in the same class. In code side they are wrapped in a class but in db they are on the same table as "Type_PropertyName", so no need to have a class with many properties that could be easly the wrapped. For this particular scenario I would not relate shipping address to profile address since: - profile address could be changed but shipping address in order not. (maybe I moved out of the parents house and update the profile address, but the shipping address should be the same as choosed in the creation contract). Any updates should be done separately, also with other kind of process (for courier). For instance one moves from europe to america, and update the profile address, but the order is shipped so the address should be the one in europe and not let the courier be in entropy. - by referencing profile address in order, you don't have consistency on the history side: at time t1 was with address1 and at t2 with address2, and not t1 with address2 (with reference and not value). - you still can create another table of shipping order address, that is 1 to 1 if you want, I thought this example suited more for the mentioned feature. A lot of people here didn't get the actual value of the feature. I worked on a Ecommerce aggregator project, so these were a few of the many requirements.

  • @jeroen7362

    @jeroen7362

    9 ай бұрын

    @@MikyShooter Yes we are on the same page, the profile address is not referenced by the order. (also not via customer). The order address should be on the order and should not be updated or used outside the fullfilling of that one order. The customer has a profile with an up to date address on it. That is on a separate table (you could have 2 addresses for a customer, one is shipping default and the other is invoice) You should not need any orders table to find the latest address for a customer when he gets on the checkout page. A customer without any orders can have an address.

  • @kennyhendricks4293
    @kennyhendricks42939 ай бұрын

    I am glad that this has been fixed

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    We're getting there :)

  • @Sander-Brilman
    @Sander-Brilman9 ай бұрын

    how would collections work with complex types? shouldnt a new table be added for that since not all db providers support the array type

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Or JSON into one column?

  • @nicolasL009
    @nicolasL0099 ай бұрын

    Very informative video! Too bad it'll take a while before I get to use EFCore 8 at my current job. Stubbled upon the issues mentioned in the video quite a few times with older EF versions. Keep up the good work :)

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    I think EF 8 will work on olders .NET versions, need to check though 🤔

  • @modernkennnern

    @modernkennnern

    9 ай бұрын

    @@MilanJovanovicTech I think they try to keep it working on the latest LTS. In this case, that is .Net 8. But I might be wrong - it might still work on .Net 6. I know that EF7 only works on 6+

  • @vallJune
    @vallJuneАй бұрын

    Hi Milan.First of all many thanks. Would you happen to know how to configure ComplexObject as an optional? Book { Author? Author}

  • @MilanJovanovicTech

    @MilanJovanovicTech

    Ай бұрын

    Not supported right now

  • @vallJune

    @vallJune

    Ай бұрын

    @@MilanJovanovicTech thank you, Milan. The OwnsOne seems to work for me

  • @kodindoyannick5328
    @kodindoyannick53282 ай бұрын

    Thanks Milan

  • @MilanJovanovicTech

    @MilanJovanovicTech

    2 ай бұрын

    Any time

  • @xiovaii
    @xiovaii9 ай бұрын

    Finally!

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

  • @astralpowers
    @astralpowers9 ай бұрын

    Collections for value objects would really be useful for my use case

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    We'll see if it makes the cut

  • @ArcaneEye

    @ArcaneEye

    6 ай бұрын

    How? I'm really curious as I can't see a situation where that would be the correct approach.

  • @phugia963
    @phugia9639 ай бұрын

    finally we can have a good EF features to support define & map value object to the database 😄

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Yes!

  • @ArcaneEye
    @ArcaneEye6 ай бұрын

    Quick question re: list of complex types. If a complex type is mapped to columns in a table alongside the entity they belong to, how would you map a list of those to the table? Isn't that exactly what navigation properties are for?

  • @MilanJovanovicTech

    @MilanJovanovicTech

    6 ай бұрын

    Lists not supported yet

  • @rusektor
    @rusektor9 ай бұрын

    Doesn't this remind [ComplextType] attribute in EF 4.0?

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Yes, these are old EF features ported to EF Core

  • @wmalgoire
    @wmalgoire9 ай бұрын

    I feel bad for people getting obsessed by the business domain trivial example and not trying to understand this new feature.. Maybe you should post a video on active listening Milan 😂😂 I mean, there are other great contents on value objects use cases and benefits. Having struggled with poor implementations and complexity of value object persistence in efcore, I'm quite excited by this new feature! Even if in the meantime we'll have to handle collections manually..but that's a good step forward and I'll use this for sure 😊 All in all, another handy feature to keep in our toolbelt 👍 Thanks for your hard work Milan 🙏

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    It doesn't matter, I'm glad people are getting value from this and understanding the Complex Types feature 😁

  • @wmalgoire

    @wmalgoire

    9 ай бұрын

    @MilanJovanovicTech Right! What matters is communicating, not trying to change people opinions 😊 And if at least one people get value, that's a win 👍

  • @kis.stupid
    @kis.stupid9 ай бұрын

    I believe you but I don't understand why that errored before? Because of the reference? It has no PK. I did notice seeding those owned types needed to be initialized as anonymous types. I think you could use Records as well, that brings along other complications ofc. I would like to learn more about those "nvarchar(max)", how to globally limit that, if you should limit that. Or how optimized that is by default.

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    It does have a "PK" as far as EF is concerned. Give it a try with Owned types and you'll see.

  • @user-gk4om7po4p
    @user-gk4om7po4p9 ай бұрын

    awesome

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Thanks a lot!

  • 7 ай бұрын

    It's not yet full supported. Complex type collection support is not ready. Check the issue 31237 and vote!

  • @MilanJovanovicTech

    @MilanJovanovicTech

    7 ай бұрын

    There's ways around that for the time being

  • 7 ай бұрын

    @@MilanJovanovicTech You could show an example of this in your videos. I am currently following Amichai's workarround "The Identity Paradox | DDD, EF Core & Strongly Typed IDs", although I don't like the arrangement too much because there is actually a small leak in the domain model that causes difficulties with the ids if it is being used the repository pattern with specification. On the other hand, I have tried creating a data model and mapping it to the domain model, but it seems like too much effort to maintain synchronization between both models. Additionally, the Id collections of my domain model are of type readonly collection. So instantiating it with automapper and EF is difficult for me and I don't think using reflection is the way to go. I look forward to your solution. Greetings :)

  • @psdmaniac
    @psdmaniac9 ай бұрын

    I have never used that. Autors should be stored is diffrent table and reused (many to many). This "own" thing looks like something against database normalization.

  • @antonmartyniuk

    @antonmartyniuk

    9 ай бұрын

    It is indeed against database normalisation. But there are certainly cases when you need to sacrifice this in favor of performance

  • @glennmerrill88ify

    @glennmerrill88ify

    9 ай бұрын

    ​@antonmartyniuk Like when? I don't see a single reason to not normalize the example shown. Why would you want a bunch of anomalies littered around your database ever?

  • @antonofka9018

    @antonofka9018

    9 ай бұрын

    ​It's going to be one less join when you query, which can be a big deal

  • @psdmaniac

    @psdmaniac

    9 ай бұрын

    Books and autors and you don't see why It should be normalized? Realy :)? What If you need to display list of autors? Will you sellect all books records and make district on autors? What if someone ask you to genereate more advance report, Daily? What about performance now :)? The solutuon is 1. Always keep your db normalized 2. Violate point 1 only if it is realy needed. For example some data redundancy is needed. And even of needed in longer period of time this bacame problematic (multiple points of truth).

  • @antonmartyniuk

    @antonmartyniuk

    9 ай бұрын

    @@psdmaniac we aren't talking specifically about this concrete example of books/authors with data normalisation. And besides, this data shape is completely valid in NoSQL world and apps have no problems with this approach

  • @gorgestv6340
    @gorgestv63409 ай бұрын

    I don't understand what is the meaning of the Owned types

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Read the docs: learn.microsoft.com/en-us/ef/core/modeling/owned-entities

  • @reelleer
    @reelleer9 ай бұрын

    Dicha funcionalidad existía en EF 6, por lo tanto ver que EF Core 8 ya la tiene me motiva a migrar mi aplicación "legacy".

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Yep, old EF features coming to EF Core

  • @fandermill
    @fandermill9 ай бұрын

    Changing the last name of the author and updating it in all books does not make sense, as ValueObjects should be immutable (well, at least from a DDD perspective). Nice feature demo though, I can't wait to clean up my dbcontext configurations.

  • @ahmedrizk106

    @ahmedrizk106

    9 ай бұрын

    I think it makes perfect sense if you are making the change on the shared author instance, but if you are making the change on the book instance it self it should not affect any other records.

  • @Code_Bits

    @Code_Bits

    9 ай бұрын

    And also using the with statement means it would set the value bypassing any guard clauses if they would be there. I'm not a fan of using Records for ValueObjects.

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    I needed a super simple example to showcase the features, so I had to "dumb" it down

  • @user-xm7sh3vw8o

    @user-xm7sh3vw8o

    9 ай бұрын

    class ->record ,yes?

  • @hanneskasel1853
    @hanneskasel18534 ай бұрын

    hmm yeah sharing instance is also not recommended whereas you shall make the complex type immutable

  • @MilanJovanovicTech

    @MilanJovanovicTech

    4 ай бұрын

    This was more about showcasing what Complex types can do, though

  • @nasermasri9954
    @nasermasri99549 ай бұрын

    First!😅

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Blazing speed!

  • @ahmedh2482
    @ahmedh24822 ай бұрын

    Doesn't this lead to redundancy in the database?!, I mean object values Why you don't use the author id instead of author object? Then you can use dto or anything to deal with your needs without overburden the database

  • @MilanJovanovicTech

    @MilanJovanovicTech

    2 ай бұрын

    Is redundancy always bad?

  • @ahmedh2482

    @ahmedh2482

    2 ай бұрын

    @@MilanJovanovicTech Suppose I'm trying to build a software for a distribution company (FMCG company), When the data entry or sales representative try to create an invoice He should determine the following The store: where the goods located, The salesman: the person who sold, The customer,... Each of the previous entities have at least 5 to 10 properties, Why I build a table in the database contains about 35 columns and most of them duplicate?

  • @skelaw

    @skelaw

    Ай бұрын

    ​​@@ahmedh2482 to preserve historical data at particullar point of time. I always store simillar info you listed in order/invoice etc. Those informations belongs to document and this is not redundant to store them, its required.

  • @jeroen7362
    @jeroen73629 ай бұрын

    I do not see the point. what does this solve? Why not have two real classes and tables? In real life an author writes 1 or more books. Why would you store the author multiple times? My advise is to not use any magic in EF core. Also implicit many2many tables that can be created by EF. Just write your own many2many class, you can then for instance put the timestamp and userid on it, who added that connection. Your are then in full control of everything.

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    You're missing the forest for the trees. This is about EF 8 Complex types. Not "correct" data modeling.

  • @jeroen7362

    @jeroen7362

    9 ай бұрын

    @@MilanJovanovicTech Yes so why am i missing the forest? I can not think of any "complex type" scenario that i would put in a database like that. Your sample with books and author sure isnt it so what real life thing would you ever put in a database like that? Only problems need a solution, i have never encountered a problem in over 20 years of software development and database design that this would solve. Edit: the order with shipping addres as mentioned here could be a scenario. Still i would not use it for that. Just add a few fields for the address, postal code and town, country and done. probably country would be a foreign key to the country table.

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    @@jeroen7362 See, there are scenarios where this is practical. You'd use an anemic model with properties for the address. Someone else prefers having a type.

  • @nick_stelmakh
    @nick_stelmakh9 ай бұрын

    the poor example. didn’t show all wide spectrum of this update

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    Now you have what to show us in your video

  • @nick_stelmakh

    @nick_stelmakh

    9 ай бұрын

    i like your videos but to be honest it so not this time, you could have spent more time giving end watchers a real example of why and for what it appeared@@MilanJovanovicTech

  • @user-rd4cd9zj1s
    @user-rd4cd9zj1s9 ай бұрын

    This is a very poor example of a Value Object. I think the feature might be useful in some scenarios, but this example is not one. It would be nice to see a real-world example instead.

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    The point is EF Complex types and how they can be used to map Value objects. This is far better than Owned types that we had thus far. And if I put too much effort into the example, it moves focus away from what I wanted to showcase here. Can't satisfy everyone

  • @AndersBaumann

    @AndersBaumann

    9 ай бұрын

    Yes. Author is definitely not a value object. Use money, address or email as examples.

  • @user-rd4cd9zj1s

    @user-rd4cd9zj1s

    9 ай бұрын

    @@MilanJovanovicTech This is the problem I run into when learning new techniques, finding bad examples and not understanding why I would want to do such a thing. I don’t use value types and your example didn’t make me understand any better as I was wondering why anyone would want to “flatten” data in a relational situation.

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    @@user-rd4cd9zj1s Funny thing is, the people who already knew about Value objects didn't think this was a bad example. And they were my target audience with this video. I didn't want to focus at all on "why" you should use a Value object. This was simply about "how" to use EF 8 Complex types to implement Value objects (and I'm kind of assuming you already know what they are, and how they fit into DDD)

  • @Dpaz2009

    @Dpaz2009

    8 ай бұрын

    @user-rd4cd9zj1s People who say this is a poor example should create a tutorial showing us better or else even better shut up and thank for sharing. 😅

  • @techpc5453
    @techpc54539 ай бұрын

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    👋

  • @greensporevalley
    @greensporevalley9 ай бұрын

    .NET stare

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    👀

  • @damiannizio4039
    @damiannizio40399 ай бұрын

    Couldn't you just have simply used conversion before? IE: builder.Property(x => x.SomeProperty).HasConversion(x => x.Value, x => new ValueObject(x));

  • @MilanJovanovicTech

    @MilanJovanovicTech

    9 ай бұрын

    How does that work for an object instead of a value?

  • @damiannizio4039

    @damiannizio4039

    9 ай бұрын

    @@MilanJovanovicTech it simply creates a column and translates the VO into primitive of value type inside value object. When the data is retrieved from database it creates a new ValueObject.

  • @damiannizio4039

    @damiannizio4039

    9 ай бұрын

    @@MilanJovanovicTech I hope that's what You meant

  • @svorskemattias

    @svorskemattias

    9 ай бұрын

    Yes that worked for single-valued value-objects! I use it all the time

  • @ArcaneEye

    @ArcaneEye

    6 ай бұрын

    ​@@svorskemattiasif you don't mind me asking, I'm having some issues doing linq .Where() queries relating to these single property value types. How do you go about that?

  • @jakelanning1535
    @jakelanning15358 күн бұрын

    Why not have an author entity and let book have an author id column with a foreign key into the authors table modelBuilder.Entity() .HasOne() .WithMany(e => e.Books) .HasForeignKey(e => e.AuthorId) .IsRequired(); Book's `public Author Author` would become `public virtual Author Author` and, as previously stated, would need a `public int AuthorId` and Author would need to have a `public virtual ICollection Books` as well as a `public int Id` I understand this is an example just to show off the feature, but i just can't imagine any case where using .OwnsOne makes more sense than to use a separate entity with a navigation property enabled by a foreign key, especially if theres a chance that the owned entity might be used in multiple of the parent entities. are joins evil and no one told me?

  • @MilanJovanovicTech

    @MilanJovanovicTech

    8 күн бұрын

    Just showcasing an EF feature here :) We're not talking about relational design 101.

Келесі