-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Improve nullability guidance for DbSets #2520
Conversation
Note that calling |
One last trick would be to do the following: class MyDbContext
{
public DbSet<Order> Orders { get; }
public SomeDbContext()
{
Orders ??= Set<Order>();
}
} Since the constructor initializes Orders, there's no nullability-related compiler warning. |
@roji Not sure I like that. It's adding dead code that will never be called just to satisfy the compiler. |
I agree it isn't ideal, but there are a number of solutions here, everyone is free to use what they like... this is an unfortunate result of the somewhat odd practice of DbContext using reflection to initialize properties in sub-classes. The solution of having the property call Set() every time is probably OK for the general case. |
Pure magic! I've always been surprised how people are happy to accept that that their DbSets are non-null without questioning how that could be the case. |
I admit I didn't question it either... until I did... |
But isn't this documentation misleading now? You're not specifying that there are "a number of solutions"; you're making a specific recommendation for one of those solutions. I'd also suggest that the wording of your recommendation is misleading; it mentions "make your DbSet properties read-only and initialize them as follows", but that code doesn't initialize a read-only property. This will likely cause confusion since the difference between |
@roji agree the updated text is clearer, thanks for listening. Here's hoping that C# 9 source generators will make this problem go away :) |
I´m not sure what you are hoping for source generators to change regarding DbSet declarations on |
As mentioned above, calling the With a source generator, the |
@irontoby that looks like #2520 (comment), which you can manually do today. Generating these directives with a source generator and a partial class seems a bit overkill to me for this problem - DbSet properties aren't typically added/removed that frequently - but it's an interesting idea! |
Note that you will have less overhead when using
IMO this is not only to satisfy the compiler. The expression bodied getter approach is also semantically more correct, as you get a immutable get-only property instead of a mutable property, which is a nice side effect. For me this does not feel like noise. It feels like the "correct" way to declare it using that style.
I´m with roji here, that this feels like a solution for a problem which does not exist. Adding new DbSets isn´t something that happens that often. Also there is very little difference between declaring |
@davidroth good points, and agree an immutable get-only property is better; I was looking at it from the standpoint that |
I still don't like the additional guidance. (To clarify, I mean the nullable field example, not the expression body example. The expression body syntax would probably be the default now if it had existed back when EF 4.1 was designed.) The cost of calling public CommunitiesContext()
{
Communities = Set<Community>();
People = Set<Person>();
}
public DbSet<Community> Communities { get; }
public DbSet<Person> People { get; } This is effectively just doing what EF is doing for you. |
@ajcvickers I agree now, based on the discussion above. My main qualm was with the term "initialize" which implied it was only set during construction. Thanks for clarifying everyone. |
Thanks @davidroth for suggesting this.
See dotnet/efcore#21608