Something I don't quite understand about Conditional Mappings - entity-framework

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.

Related

mapping generalization constraints to sql (STI approcach)

I'm trying to model the following relationships between entities, mainly consisting of a partial, disjoint generalization.
original EERD
'mapped' to relational
Since I didn't need the subclasses to have any particular attributes I decided to use the "single table inheritance" approach, added the "type" field and moved the relationships towards the parent.
After that I had two choices to make:
1- type for the "business type" attribute
2- way to constraint participation to at most one of the 4 relationships based on the type attribute
For the sake of portability and extensibility I decided to implement no.1 as a lookup table (rather than enum or a hardcoded check).
About no.2 I figured the best way to enforce participation and exclusivity constraints on the four relationships would be a trigger.
The problem is that now I'm not really sure how to write a trigger function; for instance it would have to reference values inserted into business type, so I'd have to make sure those can't be changed or deleted in the future.
I feel like I'm doing something wrong so I wanted to ask for feedback before going further; is this a suitable approach in your opinion?
I found an interesting article describing a possible solution: it feels a bit like an 'hack' but it should be working
(it's intended for SQL Server, but it can be easily applied in postgres too).
EDIT:
It consists in adding a type field to the parent table, and then have every child table reference said field along with the parent's id by using a foreign key constraint (a UNIQUE constraint on this pair of fields has to be added beforehand, since FKs must be unique).
Now in order to force the type field to match the table it belongs to, one adds a check constraint/always generated value ensuring that the type column always has the same value
(eg: CHECK(Business_type_id = 1) in the Husbandry table, where 1 represents 'husbandry' in the type lookup table).
The only issue is that it requires a whole column in every subclass, each containing the same generated value repeated over and over (waste of space?), and it may fall apart as soon as the IDs in the lookup table are modified

EF - eliminating nullable fields without changing database

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?

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.

Access the property used in mapping entity to a table in EFv4

When we have two entities in EFv4 EDM diagram and only one table for both in the database (for instance, having table Documents and entities Invoice and Qoute), table Documents having documentTypeId column as a discriminator and set this column as a discriminator in the EDM (in Table mappings), how do we read the value of this property in our code?
We cannot assign values to it because EF does it for us under the hood (based on what we entered in Table mappings for condition) but somehow I don't get it why we are also not allowed to read it.
Imo this property is already mapped so you can't map it again. It is used to determine type of materialized entity. Why do you need such column. Usually it is enough to use is operator like:
var document = context.Documents.GetById(id);
if (document is Invoice)
{
...
}
If you only need to select subtypes you can use OfType extension method like:
var invoices = context.Documents.OfType<Invoice>().ToList();
You also don't need to set this value when adding new entity because you are adding subtype - Invoice or Quote.
Edit:
As I understand from your comment you don't need this information in query. In such case you don't need to map it. Simply use partial class of your entity and add custom property which will return your string. Sound like stupid solution but actually it would be the easiest one.
Discriminator column should be part of mapping metadata so in case of T4 template generating your entities, it could be possible to update the template so it generate such property for you.
You may want to use a single-table inheritance hierarchy, as described here.
That way, you could have an abstract Document class that includes a DocumentTypeId column. Invoices and Quotes would extend this class, but specify certain DocumentTypeId filters. However, because the original class has a DocumentTypeId column, they would each have that column as well.
Another advantage to this approach is that you could create utility methods that can act on any Document, and you could pass any Invoice or Quote to these methods.

How do I get the entity framework to stop setting the rowversion field?

Im using the Entity Framework and I have a rowversion (timestamp) field on a table to use for concurrency. However, when updating the entity object, it keeps trying to set the rowversion column to null, and I get an error:
The 'VerCol' property on 'LmpDemoRequest' could not be set to a 'null' value. You must set this property to a non-null value of type 'Byte[]'.
I have the VerCol column within the entity definition, but I am unable to remove the "Setter" function.
How do I get the entity framework to stop attempting to set this column?
You can pass any arbitrary, valid values for the RowVersion fields (DateTime.Now for example). They will be overwritten with the server-generated values.
For future releases of EF, there should be support for "shadow properties", which exist in the model but not in your classes. That feature would be useful in situations such as this.
I had a case where a view included a RowVersion column from a table that was left joined in the view... so that column could be null sometimes.
But EF4 'knows' that a RowVersion column cannot be null, so even in a simple LINQ query, it was throwing an InvalidOperationException:
The 'PersonRowVersion' property on 'vVoteInfo' could not be set to a 'DBNull' value. You must set this property to a non-null value of type 'Byte[]'
I finally had to change the view to use this for the RowVersion column, so that EF would be happy:
coalesce(p._RowVersion, cast(0 as binary(6))) [PersonRowVersion]