Entity framework 6 - Access the entity object during valueConverter - entity-framework-core

I have a project with Entity Framework Core 6 for SQL. it's a large project with a lot of entities and properties (and yes, a lot...). All properties are defined not nullable (bool, int etc.) because the SQL database tables all are not-nullable columns also. All good.
But now this project must works with an Oracle database server, and here are tables with nullable columns which not match with the not nullable entities (Oracle EF cannot match nullabe column with a not-nullable directly).
Changing all columns with not nullable with default value isn't possible. And making the entities nullable give us a lot of (test) work because it hits the logical part of code.
So, my challenge is to find a solution that nullable table columns can set not-nullable entity properties with a value or default and without changing the entity set of code.
Using the ValueConverter is the first solution but it isn't possible because a null value will never be passed to a value converter.
So I try it with a shadow property. I have this:
entityTypeBuilder.Ignore(property.Name);
entityTypeBuilder.Property<int?>($"_Nullable_{property.Name}")
.HasConversion<NullableIntConverter >()
.HasColumnName(oracleColumn.ColumName);
Here I ignore the original property for EF, then I add a shadow property with converter for the nullable type (<int?>). This is the valueConverter:
internal class NullableIntConverter : ValueConverter<int, int?>
{
public NullableIntConverter()
: base(
_convertToEntityProviderExpression,
_convertToDbProviderExpression)
{
}
private static readonly Expression<Func<int?, int>> _convertToDbProviderExpression = x =>
x.GetValueOrDefault();
private static readonly Expression<Func<int, int?>> _convertToEntityProviderExpression = x => x;
}
This works, a nullable column set the shadow property but not the original property.
The solution will be setting the original property during ValueConverter. But because of static it isn't really possible. Or maybe someone have a solution here? If I have the entity object, I can use reflection for setting the original property.
I hope that someone have a tip for a solution?

Related

Entity Framework Core set column to nvarchar(max) with code first

I am using Entity Framework Core 7.0.0 and in my OnModelCreating method I am trying to specify a column to be of type nvarchar(max).
In EF6 (not Core!), we were able to do something like:
modelBuilder.Entity<Log>().Property(p => p.Errors).IsMaxLength();
However, I am not able to figure this out in EF Core. Is there something similar available in EF Core that I am missing?
I know that it would normally default all properties of type string to nvarchar(max) but I am overriding DbContext's ConfigureConventions with the following, to default all string to 50 characters:
configurationBuilder.Properties<string>().HaveMaxLength(50);
With help of [Column] data annotation:
[Column(TypeName = "nvarchar(MAX)")]
With help of Fluent API:
entity.Property(p => p.Errors)
.HasColumnName("YourColumnName")
.HasColumnType("nvarchar(MAX)");
HasColumnName: the HasColumnName attribute is applied to a property to specify the database column that the property should map to when the entity's property name and the database column name differ.
HasColumnType: the HasColumnType method is applied to a property to specify the data type of the column that the property should map to when the type differs from convention.

Map two fields to one database column

Question: Am I somehow able to map two fields of my Entity class to only one Column in the Database?
Scenario: The database is not fully normalized. There exists one Column which contains a composite information. It is not my actual use case, but an comprehensible example might be X- and Y-coordinate of a point in the plane. So the Database may contain a String 12:45 and the Entity class should contain only two integer field x width value 12 and ywith value 45.
Currently the Entity class has just two additional getter and setter for x and y and performs the proper translation. But I am wondering if there is a way to let JPA do this for me magically in the background.
I am already working with custom converter classes, e.g. for a proper mapping between between enums and database columns, but this works only for a "one-to-one" mapping between the field in the Entity class and the column in the database.
Of course it would be the most preferable way to redesign the table in the database, but that's not an option at the moment.
Vendor specific solutions are also fine.
2 Entity fields into one database column can be done fairly simply by specifying JPA use your accessor in the entity to handle the conversion:
#Entity
#Access(AccessType.FIELD)
class myEntity {
#Id
int id;
#Transient
String x;
#Transient
String y;
#Mutable //EclipseLink specific to prevent change tracking issues
#Access(AccessType.PROPERTY)
#Column(name="yourDatabaseFieldName")
private String getCoords() {
return x+":"+y;
}
private void setCoords(String coords) {
//parse the string and set x+y.
}
EclipseLink and Hibernate have transformation mappings that are able to handle the reverse; 2 or more database fields into one java property but this is outside of JPA.

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

Entity Framework Nullable Types not included in the CreateXXX Method

I'm using Entity Framework 4.0. I have tables with many nullable types. For a table XYZ the Entity Framework creates an object with an insert method named CreateXYZ, but this method only includes the parameters for non-nullable database fields.
Nullable fields can therefore not be set on the initial insert.
What is the best way to create an CreateXYZ method that can take the nullable types as well?
The nullable values are not included in the CreatedXYZ. You can assign them later.

Not nullable fields in table inheritance - EDM

I just read this nice article that taught me how to use inheritance (Table-per-hirarchy).
I was wondering, say I have a column 'HireDate' that need to use in the sub-class.
That's for sure that in the DB it has to marked as nullable, but how can I mark it not nullable in the EDM?
I tried to set it as not-nullable, but then it says that it needs a default value, and I want the default value to be DateTime.Now, not a constant value.
If a property (like HireData) is declared on a derived type and you are using TPH you should definitely be able to mark it as non-nullable in the EDM despite the fact it is nullable in the database.
In fact this ability is one of the characteristics of TPH.
...
So I looked at the blog post in question, and noticed it has a problem because it exposes the discriminator column (PersonCategory) as a property of the base Entity, which if allowed would make the type of an Entity mutable, since you could easily do this:
student.PersonCategory = 2;
Which would make Student an Administrator! And that is NOT allowed by the EF.
So if you are following this example closely that is likely to be your problem.
The column that holds the discriminator shouldn't be mapped to a Property in the EDM, it should only be used in the mapping (i.e. 'Add a Condition' under 'Maps to XXX' in the mapping window).
Solution to problem in Blog Post: Remove the PersonCategory property from Person class.
Anyway I hope this helps
Alex