Entity Framework 7 Fluent API Doesn't Recognize IsOptional() - entity-framework

I'm currently setting up my database in my Asp.Net 5 project using entity framework 7, previously with EF 6, when I wanted to make some of my columns nullable, I would use:
modelBuilder.Entity<Article>().Property(t => t.ArticleDateModified).IsOptional();
But it seems that IsOptional is not part of EF7 anymore, I was wondering how can I achieve the same thing using EF7?
Edit:
Marc's answer is indeed correct, first I though it worked because I found something that was like IsOptional:
builder.Entity<Article>().Property(t => t.ArticleDateModified).IsRequired(false);
But after I ran some test without it, it set the database column nullable because I marked it as nullable in my domain model:
public DateTime? ArticleDateModified { get; set; }
Also worth to note that when I made the DateTime non-nullable and used the IsRequired(false), I got the following error:
The property 'ArticleDateModified' on entity type 'Article' cannot be marked as nullable/optional because the type of the property is 'DateTime' which is not a nullable type. Any property can be marked as non-nullable/required, but only properties of nullable types and which are not part of primary key can be marked as nullable/optional.
so, I wonder what is the use of IsRequired(false) here if all I have to do to make a database column nullable is to make it nullable in my domain class?

Based on the note in this documentation page, it would appear that support for doing this declaratively was rescinded. To wit:
A property whose CLR type cannot contain null cannot be configured as optional. The property will always be considered required by Entity Framework.
That this was intentional can be seen in the design discussions from the project hosting on GitHub, specifically:
That is, a property marked as nullable supports null values, while a property marked as non-nullable must never contain null values. It follows from this that marking a property which is of a non-nullable CLR type as allowing nulls will not be allowed. This is different from the EF6 behavior where this is allowed. [emphasis added]
The upshot is, in EF7 a NULL column strictly implies a nullable mapped property. If your property is nullable, the associated column must be NULL unless you mark or configure it with IsRequired.
Response to OP edits
That's interesting, I didn't initially see the documentation on an IsRequired(bool) API. I found a discussion point on it in some June meeting notes that state that this would be the equivalent of EF6's IsOptional():
.IsOptional() - We'll provide this functionality via calling Required(false)
.IsRequired() - Provide Required() with the same functionality
Even though this was the original intent, the design decision to rescind support dates from October. (Per update) attempting to set IsRequired(false) on a non-nullable property results in a run-time error, rather than having been removed entirely.
Though now superfluous, the API cannot be removed without breaking valid code: it wasn't implemented with separate IsRequired(bool) and IsRequired() definitions, but with a single IsRequired(bool required = true). If it were removed and replaced with the parameterless version it would be a breaking change.

Em... Declare Property as nullable?
class Article
{
public DateTime? ArticleDateModified {get;set;}
}

There is not IsOptional in EntityFrameworkCore but there is IsRequired to do the oposite. By default field are nullable if the C# type is nullable.
And more over you cannot set the foreign key which is the primary key of another table using the IsRequire(false) method. if you do so EntityframeworkCore throw an error.
public class User
{
public int Id {get; set;}
public string Username {get;set}
public byte Interest {get;set;}
public Interest Interest {get;set;}
}
public class Interest
{
public byte Id {get;set;}
public string Name {get;set;}
}
ApplicationDbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>()
.property(u => u.InterestId)
.isRequired(false);
}
Error
The property 'InterestId' on entity type 'User' cannot be marked as nullable/optional because the type of the property is 'byte' which is not a nullable type. Any property can be marked as non-nullable/required, but only properties of nullable types and which are not part of primary key can be marked as nullable/optional.
So the best way is to make the property nullable like this.
public byte? InterestId {get; set;}
public Interest Interest {get; set;}

Related

The entity type 'XmlSchemaCompilationSettings' requires a primary key to be defined. If you intended to use a keyless entity type

I'm trying to do add-migration connecting to Postgres using EFcore but failing with below error.
The entity type 'XmlSchemaCompilationSettings' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
i found the issue
One of the entity class had a XMLDocument variable, when I changed it to string it started working.
public XmlDocument? InputFile {get; set;}
changed to
public string? InputFile {get; set;}

Can EF Core configure a "real" One-To-One relation where both ends are required?

The EF Core documentation about One-To-One relations says: "When configuring the relationship with the Fluent API, you use the HasOne and WithOne methods." A closer look shows that this configures One-To-ZeroOrOne or ZeroOrOne-To-ZeroOrOne relations depending on whether IsRequired is used or not. Example:
public class ParentEntity
{
public Int64 Id { get; set; }
public ChildEntity Child { get; set; }
}
public class ChildEntity
{
public Int64 Id { get; set; }
public ParentEntity Parent { get; set; }
}
The derived context class contains:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ParentEntity>().HasOne(p => p.Child).WithOne(d => d.Parent)
.HasForeignKey<ChildEntity>("ParentFk").IsRequired();
}
With this configuration, context.SaveChanges fails after context.Add(new ChildEntity()) as expected (with SqlException: Cannot insert the value NULL into column 'ParentFk' ... because of IsRequired) but succeeds after context.Add(new ParentEntity()) and context.Add(new ChildEntity() { Parent = new ParentEntity() }), i.e., the ParentEntity-ChildEntity relation is One-To-ZeroOrOne. In other words: the parent of a child is required, the child of a parent is optional.
Is there a way to configure a "real" One-To-One relation where both ends are required?
Maybe this cannot be enforced within the database. But can it be enforced by EF Core? (BTW: It can be enforced by EF6.)
Is there a way to configure a "real" One-To-One relation where both ends are required?
At the time of writing (EF Core 2.1.2), the answer is (unfortunately) negative.
The Required and Optional Relationships section of the documentation says:
You can use the Fluent API to configure whether the relationship is required or optional. Ultimately this controls whether the foreign key property is required or optional.
There is also a closed issue EF Core 2: One to One Required Not Being Enforced (also Navigation no longer needed?) #9152 asking the same question, and part of the response is:
when a relationship is made "Required" it means that a dependent entity cannot exist without an associated principal entity. This is done my making the FK non-nullable--i.e. the FK value must reference some principal entity.
However, it says nothing about the principal entity existing without the dependent. This is always possible because there isn't really any way to restrict it when working with partially loaded graphs. (This was the same with the old stack, although there were some situations where the state manager would, almost arbitrarily, stop certain things happening.) With stronger semantics applied to aggregates that limit partially loading of graphs it may be possible to enforce such a restriction in the future, but that isn't done yet.

How to add Foreign Key Properties subsequently to a Code First Model?

Given the Model:
Public Class Customer
Property Id() As Guid
Property FirstName() As String
Property MiddleName() As String
Property LastName() As String
Property Addresses() As ICollection(Of Address)
End Class
Public Class Address
Property Id() As Guid
Property Name() As String
Property Street() As String
Property City() As String
Property Zip() As String
Public Property Customer() As Customer
End Class
Entity Framework 6 Code First has created a column called Customer_Id in my table Addresses. Now, I'd like to add a Property Customer_Id to my class Address that represents the existing foreign key relation:
Public Class Address
Property Id() As Guid
Property Name() As String
Property Street() As String
Property City() As String
Property Zip() As String
Public Property Customer() As Customer
//Added
Public Property Customer_Id() As Guid
End Class
Unfortunately this results in an InvalidOperationException while creating the DbContext saying:
The model backing the 'DataContext' context has changed since the database was created.
I tried different property names (with and without underscore, different casing). But still no luck. So, what is the correct way to add those properties subsequently without the need for migrations? I assume it's possible, because the model does not really change, I am only changing from an implicit declaration of a property to an explicit...
Update:
The responses show me, that I did not explain the problem very well. After some more reading I found the correct names now: I have an application which is installed several times at customer locations (therefore dropping and recreating the database is no option). Currently, it depends on Entity Framework's Independent Associations, but I want to have the Foreign Key in my entity as well (this is no change to the model, the foreign key is already there, but does not exist as a property in my entity, since this is currently only relying on the IA instead). I did not manage to add it without EF thinking my Database is outdated.
for me two ways :
drop table __MigrationHistory : that is have the new model runs, but forget migration functionalities
create a new db by changing the connection string of the application. Replace old __MigrationHistory by __MigrationHistory of the newly created db
Never tested the second solution, but it should work.
Before using any solution:
backup you db.
Before using first solution: are you sure you will never need migration functionalities ?
This exception is because you change your model. You have to set migration strategy. Please look at:
http://msdn.microsoft.com/en-us/data/jj591621#enabling
(edited)
First of all you have to remove that exception. Even if you didn't add any new column to your database your model has changed because you added new property to Address class. If you check your DB you will find dbo.__MigrationHistory table with Model column. Last (earliest) value from that column is used for checking that your model and DB are compatible. I'm not sure but I think that EF stores there binary serialized model. So the solution is - recreate DB or add migration (probably empty migration).
(edited)
When you want to set FK you can do this very simple by Data Annotations
// c# example
public class Address
{
...
public string CustomerId { get; set; }
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
}
or in fluent api
// c# example
modelBuilder.Entity<Address>()
.HasRequired(arg => arg.Customer)
.WithMany()
.HasForeignKey(arg => arg.CustomerId);
or look at:
http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx
http://msdn.microsoft.com/en-us/data/hh134698.aspx

Breeze is trying to update a computed database column

A friend reported a problem with a computed column, Entity Framework, and Breeze
We have a table with a "FullName" column computed by the database. When creating a new Person, Breeze sends the FullName property value to the server, even though it’s not being set at all, and that triggers an error when trying to insert the new Person instance. The database throws this exception:
The column "FullName" cannot be modified because it is either a computed column or is the result of a UNION operator.
Here is the relevant portion of the SQL Table definition:
CREATE TABLE [dbo].[Person](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[FirstName] [varchar](100) NULL,
[MiddleName] [varchar](100) NULL,
[LastName] [varchar](100) NOT NULL,
[FullName] AS ((([Patient].[LastName]+',') + isnull(' '+[Patient].[FirstName],'')) + isnull(' '+[Patient].[MiddleName],'')),
...
My friend tells me the corresponding "Code First" class looks something like this:
public class Person {
public int ID {get; set;}
public string FirstName {get; set;}
public string MiddleName {get; set;}
public string LastName {get; set;}
public string FullName {get; set;}
...
}
The answer to this question explains the problem and offers a solution.
Design issues
Everyone looking at this wonders why there is a computed column for FullName and, secondarily, why this property is exposed to the client.
Let's just assume there is a good reason for the computed column, a good reason for the model to get the value from the table instead of calculating the value itself, and a good reason to send it to the client rather than have the client calculate it. Here's what he told me about that;
"We need to include the FullName in queries"
Life works out this way sometimes.
Consequences
Notice that the FullName property has a public setter. The EF metadata generator for the Person class cannot tell that this is a read-only property. FullName looks just like LastName. The metadata say "this is normal read/write property."
Breeze doesn't see a difference either. The client app may not touch this property, but Breeze has to send a value for it when creating a new Person. Back on the server, the Breeze EFContextProvider thinks it should pass that value along when creating the EF entity. The stage is set for disaster.
What can you do if (a) you can't change the table and (b) you can't change the model's FullName property definition?
A Solution
EF needs your help. You should tell EF that this is actually a database computed property. You could use the EF fluent interface or use the attribute as shown here:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public String FullName { get; set; }
Add this attribute and EF knows this property is read-only. It will generate the appropriate metadata and you can save a new Person cleanly. Omit it and you'll get the exception.
Note that this is only necessary for Code First. If he'd generated the model Database First, EF knows that the column is computed and doesn’t try to set it.
Be aware of a similar issue with store-generated keys. The default for an integer key is "store-generated" but the default for a Guid key is "client generated". If, in your table, the database actually sets the Guid, you must mark the ID property with [DatabaseGenerated(DatabaseGeneratedOption.Identity)]

Why is entity framework not annotating some non nullable columns as required?

I am using EF 4.1 with database first.
Example table:
CREATE TABLE dbo.Foo(
[ID] [int] IDENTITY(1,1) NOT NULL,
Created datetime not null default(getdate()),
Title varchar(80) not null
PRIMARY KEY CLUSTERED ([ID] ASC)
)
EF correctly loads the model with all 3 columns as nullable = false.
Output from code generation item "ADO.NET DbContext Generator":
public partial class Foo
{
public int ID { get; set; }
public System.DateTime Created { get; set; }
public string Title { get; set; }
}
In MVC3 I generate the FooController via the db context and foo model. When I bring up /Foo/Create and hit "Create" on the blank form it shows a validation error on "Created" field but not on "Title".
If I enter only a "created" date I get an exception:
Validation failed for one or more entities. See 'EntityValidationErrors'
property for more details
The exception is "The Title field is required".
I'm not sure why it works fine for one column but not the other. My first fix was to simply add the annotation, however the class code is auto generated by EF.
The only fix that seems to work is to use a partial metadata class: ASP.NET MVC3 - Data Annotations with EF Database First (ObjectConext, DbContext)
I can add the [Required] tag as desired however this should be unnecessary. Is this a bug in EF or am I just missing something?
This isn't a bug, EF simply doesn't add those attributes. As far as i know, the database-first approach (Entity classes generated by the designer) doesn't even perform the validation. The link you're refering to is a valid solution for your problem. The principle of buddy-classes which contain the actual metadata was introduced due to the fact, that you cannot add attributes to existing properties in a partial class.
The code-first approach has a built-in functionality to validate your annotations, see: Entity Framework 4.1 Validation. Another solution when using database-first would be to create a custom code-generator that applies those attributes T4 Templates and the Entity Framework.