I would like to use EF core with nullable reference types configured by fluent annotations.
I want to model a one-to-one relationship where SomeEntity has an OtherEntity called Relation, and OtherEntity optionally has a SomeEntity.
Because I don't want to always load the relation, I define OtherEntity as nullable, since it will be null if it's not loaded:
public class SomeEntity {
public virtual OtherEntity? Relation {get;}
}
However, when I use this definition to build a model, OtherEntity becomes nullable in the database definition. That's not my intention: it should be required, in the database, just not necessarily loaded in the code.
How do I model this in such a way that it's clear the value could be null at runtime, but has a database backing store with a column that's not null?
I prefer not to adjust the code of the entity for this purpose, but if there is no other way, that will have to do.
Related
So I'm transferring domain classes (a lot) to the postgres with EF6.
Classes can have value type properties, like int and float, and are being transferred to postgres as NOT NULL.
I can't make my domain classes properties nullable, as it could break business logic.
I saw this approach - make props optional
but this means that I have to manually do this in OnModelCreating in my dbcontext for every class I Have, right?
So, is there any way to make value types (for all my domain classes) nullable in database, like, at initial migration (or any other way in bulk) - so I dont have to manually specify it in OnModelCreating for every class I have? Maybe it is possible with some custom convention for it?
tldr - I want to make evey value type property of every class nullable in database with ef6, without making it nullable in domain itself
Thanks!
There is a DbModelBuilder.Properties() method.
It can be used to set the necessary values for all properties in the OnModelCreating method.
modelBuilder.Properties().Configure(p => p.IsOptional());
However, this will change all properties. Of course, there is no need to change the primary keys and some other columns. Therefore, they need to be filtered out.
modelBuilder.Properties().Where(p => p.Name != "Id").Configure(p => p.IsOptional());
Or something like that:
modelBuilder.Properties().Where(p => p.Name.EndsWith("Id")).Configure(p => p.IsOptional());
Did you try in your Domain classes ? Nullable value types
public class Book
{
public int ID { get; set; }
public double? Price { get; set; }
}
Consider these simple classes. They belong to a simple application with Domain Driven Design (DDD) principles, and as such every Entity and ValueObject receives its property values through the constructor while hiding the default, parameter-less constructor. Properties will also be read-only.
public class MyClass
{
public Guid Id {get;}
public ValueObject ValueObject1 {get;}
public ValueObject ValueObject2 {get;}
public MyClass(ValueObject valueObject1, ValueObject valueObject2)
{
ValueObject1 = valueObject1;
ValueObject2 = valueObject2;
}
private MyClass(){}
}
public class ValueObject
{
public string Value {get;}
public ValueObject(string value)
{
Value = value;
}
private ValueObject(){}
}
I want to be able to create a database based on this model, using EntityFramework Core 2.2.6.
Apparently EF Core 2.2.6 can automatically feed property values for these classes through their parametrized constructors, as long as constructor parameters and class properties have the same name (case-insensitive). Great.
Now I want the ValueObjects to be stored in the same table as the MyClass. To make that happen, I am told, I should use modelBuilder.OwnsOne<> in OnModelCreating of the DBContext, instead of modelBuilder.Property<>
The DBContext configuration in OnModelCreating would look like something this:
modelBuilder.Entity<MyClass>(b => b.HasKey(mc => mc.Id));
modelBuilder.Entity<MyClass>(b => b.OwnsOne(mc => mc.ValueObject1,rb =>
{
rb.Property(vo => vo.Value);
}));
modelBuilder.Entity<MyClass>(b => b.OwnsOne(mc => mc.ValueObject2, rb =>
{
rb.Property(vo => vo.Value);
}));
Now it seems modelBuilder.OwnsOne<> and modelBuilder.Property<> are mutually exclusive, meaning you can't use them both together because every time I try to Add-Migration with both of them I get:
'ValueObject' cannot be used as a property on entity type 'MyClass' because it is configured as a navigation.
But if I don't use modelBuilder.Property<> and only use modelBuilder.OwnsOne<>, I get:
No suitable constructor found for entity type 'MyClass'. The following
constructors had parameters that could not be bound to properties of
the entity type: cannot bind 'valueObject1', 'valueObject2' in
'MyClass(ValueObject valueObject1, ValueObject valueObject2)'.
Which means the constructor to property binding pattern only works only if I use modelBuilder.Property<> to configure the properties on MyClass.
So my question is: how should I configure the DBContext to allow EF Core to both set property values through the parametrized constructor, and store ValueObjects in the same table as the Entity?
So here is what happened.
As #Gert Arnold pointed out:
1. You need to have private setters on all properties of your domain models. EF Core can't work with read-only properties as of version 2.2.6.
But that was not my problem. It turned out I had forgotten to include a private constructor on the equivalent of MyClass in my own project. I just wish I had seen #Ivan Stoev's comment before I spent hours of work and figured it out. The error message that EF Core gave me was too cryptic, and didn't point out the issue:
No suitable constructor found for entity type 'MyClass'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'valueObject1', 'valueObject2' in 'MyClass(ValueObject valueObject1, ValueObject valueObject2)'.
When in reality, there is no problem with that particular constructor.
2. You just have to have a private, parameter-less constructor if you want EF Core to properly use constructor binding and feed values to your properties through constructor parameters.
This is not the case. EF Core simply can't inject entities into other entities using constructor binding.
It is basically telling us that particular constructor can't be used, and because it can't find a suitable constructor to use, at all, by providing a parameter-less constructor you are giving it a way to create objects without constructor binding.
3. You should use modelBuilder.OwnsOne<> in your DbContext.OnModelCreating and NOT modelBuilder.Property<> to configure Value Objects for an Entity (in DDD) to be stored in the same database table as the Entity.
I think EF Core needs to give you a clearer message about how it is confused as to which constructor it should use when you don't have a private, parameter-less constructor. I'll bring it up with the EF Core team.
We are reviewing two different methods in generic repository patterns.
Currently, want to map primary keys to Ids. The purpose of this is to map to the Generic Repository Interface which utilizes Id. Two solutions are provided below.
What are performance implications of .FindPrimaryKey().Properties. Does it cause a schema lock on database table in trying to find the primary key? Does it cause any application slowness?
How does it compare in performance vs Partial Class Method Solution 2?
What option is better performance-wise?
Note: Architects demand the use of repository pattern at the workplace, so implementing it. Know there is debate surrounding this issue, but not my call.
Scaffolded Model Example:
namespace Datatest
{
public partial class Property
{
public int Property { get; set; }
public int DocumentId { get; set; }
public string Address { get; set; }
}
}
Sample Generic Base Repository for all tables:
public T Get(int id)
{
return Table.Find(id);
}
public async Task<T> GetAsync(int id)
{
return await Table.FindAsync(id);
}
public T Single(Expression<Func<T, bool>> predicate)
{
return All.Single(predicate);
}
public async Task<T> SingleAsync(Expression<Func<T, bool>> predicate)
{
return await All.SingleAsync(predicate);
}
public T FirstOrDefault(int id)
{
return All.FirstOrDefault(CreateEqualityExpressionForId(id));
}
Solution 1: FindPrimaryKey()
Generic Repository in C# Using Entity Framework
use EF FindPrimaryKey()
var idName = _context.Model.FindEntityType(typeof(TEntity))
.FindPrimaryKey().Properties.Single().Name;
Solution 2: Partial classes Mapping
Net Core: Create Generic Repository Interface Id Mapping for All Tables Auto Code Generation
public partial class Property: IEntity
{
[NotMapped]
public int Id { get => PropertyId; set => PropertyId = value; }
}
Regarding the first approach (using EF Core metadata services):
First, EF Core is ORM (Object Relational Mapper), with most important here is Mapper.
Second, it uses the so called code based model, which means all the mappings are provided by code and not the actual database (even though the model is created by reverse engineering of an existing database).
In simple words, EF Core creates at runtime a memory data structure containing the information (metadata) about classes and properties, and their mappings to database tables, columns and relationships. All that information is based on pure code model - the entity classes, conventions, data annotations and fluent configuration.
All EF Core runtime behaviors are based on that metadata model. EF Core uses it internally when building queries, mapping the query results to objects, linking navigation properties, generating create/update/delete commands and their order of execution, updating temporary FK property values after getting the real autogenerated principal key values etc.
Hence the metadata model and discovering services (methods) use optimized data structures and are (has to be) quite efficient. And again, no database operations are involved.
So the first approach is quite efficient. The performance impact of obtaining the PK property name via metadata service is negligible compared to actual query building, execution and materialization.
Also the performance of the first approach is similar to EF Core Find method which you are using in another method. Note that when calling Find method you just pass the PK value(s) and not the properties. So the method implementation should somehow know how to build the Where expression, right? And what it does internally is very similar to the suggested snippet.
Regarding the second approach:
It's simply not comparable because it doesn't work. It's possible to use base class/interface, but only if the actual property name is mapped - like all classes have Id property, and it's mapped to different column name in the database tables using [Column] data annotation or HasColumnName fluent API.
In your example, the Id property is [NotMapped] (ignored). Which means EF Core cannot map to the table column. The fact that your are mapping it to another property via code (property getter/setter) doesn't matter. EF Core is not a (de)compiler, it can't see your code, hence cannot translate a LINQ query using such properties to SQL.
Which in EF Core 2.x leads to either client evaluation (very inefficient, reading to whole table and applying the filter in memory), or exception if client evaluation is configured to do so. And in EF Core 3.0+ it will always be an exception.
So in case you don't remove properties like PropertyId and map the property Id (which would be hard with "database first" models), the second "approach" should be avoided. And even if you can map the actual Id property, all you'll save would be a few milliseconds. And again, when using Find you don't bother about performance, why bother with methods that uses the same (or similar) approach.
Is it possible to have Entity framework generate a table, from a model, with the column marked as not null without using the [Required] annotation on the model's property?
Reason:
The object is posted to an api and I check ModelState.IsValid in the controller. The property is supposed to be generated server side and not come from outside, but if I have the property [Required] the ModelState.IsValid is false (in which case I return with a BadRequest(ModelState);).
Can I tell EF to make the column not null in some other way?
I guess another solution would be to expect another object(some sort of DTO) to be sent to the api and then do a mapping. But that object would look exactly the same save for this single property, which makes it seem a bit unnecessary, right?
Use Fluent API and IsRequired method in your DbContext class like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<YourEntity>().Property(t => t.YourProperty).IsRequired();
base.OnModelCreating(modelBuilder);
}
If I were you I would not use Entity Framework's entities directly, I would use a DTO first and map it into a EF Entity, why? Because your DTO and EF Entity have not the same responsibility.
DTO : Data transfer object, so just use it to transfer data
EF Entity : it's the model binding to your database.
I'm looking for some advice. I'm working with EF 5 and I have a generic repository which handles all of the CRUD transactions with the database. This works fine, But i want to add a "Last Gap" safeguard to ensure that the entity is valid before the Data Access Layer attempts changes in the database.
Right before I do something like this :-
DataLayer.Create<TEntity>(entity);
I want to Validate the entity and throw an exception if the validation fails.
What would you guys use as the preferred method?
Using Data Annotations
You can use data annotations directly in your entity. With data annotations, EF will validate the property for you and if it is not valid, an exception will be thrown.
For example, if you want Name to be required, you can do something like:
public class Person
{
[Required]
public string Name { get; set; }
// other members
}
Aside from validation, EF will also set the corresponding column to be not null instead of the default null for strings.
Using the Fluent API
If you don't want to litter your entities with data annotations, you can use the fluent API instead. Following is the equivalent of the above code:
public class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Entity<Person>().Property(p => p.Name).IsRequired();
}
// other members
}
My answer applies to EF Code First and may not apply for other workflows.
Sometimes you have to go to the database to check whether inserting or updating an entity keeps the repository in a valid state - such as when you need to ensure the natural key is unique. That isn't currently handled by a data annotation or the Fluent API, although it has been discussed. See unique constraints in entity framework And this work item.
In the meantime, when you have to go to the database then DbContext will be involved somewhere, and DbContext has an Overridable method called ValidateEntity. See this article: Entity Framework Validation.
I put the code I use in another answer here
And more about how I've structured the validation in MVC here.
I wouldn't do validation at the DAL, but if you do, you might be interested in Validation with the Data Annotation Validators