EF - eliminating nullable fields without changing database - entity-framework

We have a large legacy transactional-type SqlServer database with hundreds of tables, and most of the fields in these tables have the Allow Null attribute turned on.
We are also using Entity Frameworks and are developing a new C# to access the database. In the POCO classes generated by EF, the field properties have, of course, the Nullable decorator, which produces nullable data types (e.g., "int ?").
The impact is that if any given field contains null and we don't explicitly check for null before accessing the field, the app will blow up. Each field also has to be casted for use, or the Value property has to be used.
We could, of course, changes the schema and turn off the Allow Null property, but are getting push-back from the DBA's who want to avoid making any changes.
Is there a way in the EF generator to turn off the Nullable attribute for some or all fields, and coerce the logic to return default values for null fields (e.g., 0 for int, false for bool, etc.) on select statements, and to use default values for inserts/updates?

Related

How to create relationships between entities with existing database that does not contain foreign keys

Using Entity Framework Core 2.0
Stuck with company's production database which has primary keys defined for each table but no foreign keys defined for any relationships.
Dependent records in the database have id fields which are intended to relate to the primary key fields of the parent record like you would normally find with a foreign key relationship/constraint. But these fields were all created as INT NOT NULL and are using a SQL default of '0'.
As a result dependent records have been inserted over time without requiring that a related parent record be specified.
Initially I defined my models in EF with integers and used a fluent configuration to specify "IsRequired". This was done so I could run migrations to create a test database for comparison against the production database to verify that my code first was correctly coded.
This then lead to the problem while using "Include" in my Linq queries which performs an inner join that results in dropping the records that contain the 0's in the id fields of the dependent record.
The only way that I have found to make this work is to model all of the id fields in the dependent entity as nullable integers and remove the "IsRequired" from the fluent configuration.
When using the "Include" it performs a left outer join keeping all of the dependent entities. This also means that any reference properties on the included entities are set to null instead of an empty string. This part can probably be fixed fairly easily.
The downside is if I wanted to use migrations to create a database now, all id fields in the dependent records would be created as NULL.
Is there anyone who has run up against this type of situation? Does anyone have any suggestions to try other than the approach I am using?
I haven't dealt with this scenario before but I wonder if you can solve it by defining the FK property as Nullable and then in the migrations, after the migration is created, edit it to add a HasDefaultValue property to ensure that it's 0? (doc for that migration method: https://learn.microsoft.com/en-us/ef/core/modeling/relational/default-values)

entity framework working with entity properties that are null

In Entity framework, I am having entity properties which correspond to SQL Table columns which are ALLOW NULL = True in Database. When I use those properties in C#, if the value is null it gives exception. So how to handle this in EF, this happens for all the table columns that allow null.
I am assuming these columns are Nullable type in your .NET code, since they have ALLOW NULL = True in database. So, everytime you use these values, check for PropertyName.HasValue() which returns false whenever the property is null.

Something I don't quite understand about Conditional Mappings

In most cases, we can map a field in a table either to a property or we can map it using conditional mapping, but not both. Only exception is if condition is set to Is NotNull, since then we can also map to a column.
a) Is this the reason why we are able to map a DB column only once - namely, if field was allowed to have both a property mapping and a conditional mapping, then property mapping would tell EF to retrieve all table rows, while conditional mapping would tell EF to retrieve only those rows that satisfy the condition?!
b) If my reasoning under a) is correct, then why is field allowed to have both mappings when condition is set to Is NotNull? Why won't that create a conflict?
Thank you
Mapping with condition Is NotNull has special meaning because it requires subsequent change in your model. The mapped property in the model must not be nullable. So your column in the database is nullable, your mapping condition filters all records with null value and your property always receives only records with non-null values. Also you can never assign null to the property.
In case of common condition with value equality this special behaviour is not possible.

Supporting default column values in custom Entity Framework provider

I'm working on a custom entity framework provider and I need to add support for default column values for this provider. When the user uses the entity framework wizard and selects a table that includes columns with default values, those default values are not being populated into the entity designer.
I'm a little lost on where exactly this population should take place. I believe the appropriate place would be in the GetEdmType method override of DbXmlEnabledProviderManifest but I just don't see how to set the default value, if this is the correct place.
Anybody has experience writing EF providers that support default values for table columns? How do you implement this?
I am a bit late to the party but DbXmlEnabledProviderManifest is not the right place for adding default values. The provider manifest describes capabilities of the database engine itself and is specific (and general) to this database engine and not to a given database and/or table. The default value in the provider manifest tells EF what value to use for the given column property if one is not provided by the user (e.g. if the user user does not specify scale or precision for a decimal column the value from provider manifest will be used for scale and/or precision used for this column).
If you want just to insert a default value for a property the easiest way is to set the property that corresponds to the column on your entity to this value in the constructor. This way the user can always set it to a different value but if s/he does not the default value will be sent to the database. For some corner case scenarios where some of the columns in the database do not have corresponding properties on entities you can use DefaultValue attribute on the Property element in SSDL which will be inserted to the database when you add a row. This is especially useful if those properties are not nullable since without telling EF what value should be inserted EF would try inserting null which would obviously fail for non-nullable columns.

EF Table-per-hierarchy mapping

In trying to normalize a database schema and mapping it in Entity Framework, I've found that there might end up being a bunch of lookup tables. They would end up only containing key and value pairs. I'd like to consolidate them into one table that basically has two columns "Key" and "Value". For example, I'd like to be able to get Addresses.AddressType and Person.Gender to both point to the same table, but ensure that the navigation properties only return the rows applicable to the appropriate entity.
EDIT: Oops. I just realized that I left this paragraph out:
It seems like a TPH type of problem, but all of the reading I've done indicates that you start with fields in the parent entity and migrate fields over to the inherited children. I don't have any fields to move here because there would generally only be two.
There are a lot of domain-specific key-value pairs need to be represented. Some of them will change from time to time, others will not. Rather than pick and choose I want to just make everything editable. Due to the number of these kinds of properties that are going to be used, I'd rather not have to maintain a list enums that require a recompile, or end up with lots of lookup tables. So, I thought that this might be a solution.
Is there a way to represent this kind of structure in EF4? Or, am I barking up the wrong tree?
EDIT: I guess another option would be to build the table structure I want at the database level and then write views on top of that and surface those as EF entities. It just means any maintenance needs to be done at multiple levels. Does that sound more, or less desireable than a pure EF solution?
Table per hiearchy demands that you have one parent entity which is used as base class for child entities. All entities are mapped to the same table and there is special discriminator column to differ type of entity stored in database record. You can generally use it even if your child entities do not define any new properties. You will also have to define primary key for your table otherwise it will be handled as readonly entity in EF. So your table can look like:
CREATE TABLE KeyValuePairs
(
Id INT NOT NULL IDENTITY(1,1),
Key VARCHAR(50) NOT NULL,
Value NVARCHAR(255) NOT NULL,
Discriminator VARCHAR(10) NOT NULL,
Timestamp Timestamp NOT NULL
)
You will define your top level KeyValuePair entity with properties Id, Key, Value and Timestamp (set as concurrency mode fixed). Discriminator column will be used for inheritance mapping.
Be aware that EF mapping is static. If you define AddressType and Gender entities you will be able to use them but you will not be able to dynamically define new type like PhoneType. This will always require modifying your EF model, recompiling and redeploying your application.
From OOP perspective it would be nicer to not model this as object hiearchy and instead use conditional mapping of multiple unrelated entities to the same table. Unfortunatelly even EF supports conditional mapping I have never been able to map two entities to the same table yet.