Skip to content

Compex types inconsistencies?: Record struct vs record for Requrired and ComplexType attribute, how to deal with Default values? #32404

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

Closed
andrerom opened this issue Nov 24, 2023 · 6 comments

Comments

@andrerom
Copy link

andrerom commented Nov 24, 2023

As code first developer, attempting to write DB provider agnostic code, I'm expecting to be able to configure everything with inline attributes on my models to keep everything in one place.

These topics comes from trying to follow usage examples from among others:
https://devblogs.microsoft.com/dotnet/announcing-ef8-rc1/#configuration-of-complex-types
https://www.learnentityframeworkcore.com/model/complex-type

Questions / Bugs(?)

1. RequiredAttribute bug?

For record this attribute is required to be able to generate migration, but that is not the case if complex type is record struct where migration is then happily generated without any b1.IsRequired(); in ApplicationDbContextModelSnapshot.cs.

[Required]
public required Address DeliveryAddress { get; set; }

Ideally as a code first developer I'd like it to be enough to specify required keyword, in both cases (class and struct).

2. ComplexTypeAttribute bug?

The initall blog post introducing Complex types seems to (kind of) recommend using record structs for it's value type semantics.

However ComplexTypeAttribute is not allowed on structs, IDE gives: Attribute 'ComplexType' is not valid on this declaration type. It is only valid on 'class' declarations.[CS0592]

[ComplexType]
public record struct Address

Ideally as a code first developer I'd expect it to work on both (class and struct).

3. How to set Default value on complex type properties?

So complex properties are for now required only, however there are complex type properties you'd like to set default values for, also in database in case of custom sql inserts (data migration or otherwise).

Ideally as a code first developer I'd expect it to be able to use DefaultValueAttribute or similar to set DB provider agnostic default values for normal properties as well as properties on complex types:

[DefaultValue("US")]
public string CountryCode { get; set; } = "US";

Or even better, a way to get EF to carry on default values from code to generates schema? (with possiblity to opt out):

public string CountryCode { get; set; } = "US";

Provider and version information

EF Core version: 8.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer (for now)
Target framework: .NET 8.0
Operating system: Mac (ARM64)
IDE: VS Code

@andrerom andrerom changed the title Compex types inconsistencies?: Record struct vs record for Requrired and ComplexType attribute, & how to deal with Default values? Compex types inconsistencies?: Record struct vs record for Requrired and ComplexType attribute, how to deal with Default values? Nov 24, 2023
@ajcvickers
Copy link
Contributor

For record this attribute is required to be able to generate migration, but that is not the case if complex type is record struct where migration is then happily generated without any b1.IsRequired()

[Required] should not be needed for a record type if the property is nullable reference types are enabled and the property is non-nullable. If the property is nullable, then [Required] is needed since EF currently doesn't support nullable complex type properties (#31376).

Ideally as a code first developer I'd like it to be enough to specify required keyword

The required keyword does not map to any concept in the database and is not used by EF to change any behaviors. a required property can be nullable or non-nullable, and the value set can be null.

However ComplexTypeAttribute is not allowed on structs

See #31618.

Ideally as a code first developer I'd expect it to be able to use DefaultValueAttribute

See #19546.

@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Dec 5, 2023
@nabeelio
Copy link

nabeelio commented Apr 4, 2024

I know this is closed, but this is a little confusing because the docs say that structs can be complex types. I guess that's through Fluent only? I have a lot of usages of complex types (I have a struct for geo coordinates and I'm storing lengthy paths of different types)

@roji
Copy link
Member

roji commented Apr 4, 2024

@nabeelio complex types in general need to be configured via the Fluent API, regardless of whether they're structs or not. But you can bulk-configure a CLR type to always be mapped as a complex type:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.ComplexProperties<Blog>();
}

@nabeelio
Copy link

nabeelio commented Apr 4, 2024

Thanks! I had just found that out last night and was gonna comment back here tomorrow for anyone else to find. Much appreciated!

@dvisentin-freelance
Copy link

@roji

complex types in general need to be configured via the Fluent API, regardless of whether they're structs or not

That doesn't seem correct to me. When I use, for example, a record class, it seems that using [ComplexType] is enough.

@roji
Copy link
Member

roji commented Aug 24, 2024

@dvisentin-freelance you're right - my comment was incomplete. But my point was that explicit configuration is needed, and [ComplexType] is another type of explicit configuration (via attribute instead of via the Fluent API).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants