Entity Framework 6.1 explicit Discriminator column - c#

I am using code-first method to generate my DB. In one of the cases, there is an inheritance hierarchy which gets correctly mapped to a TPH scenario. However, the Discriminator column which gets created (automatically) isn't available in the base C# class.
I want the base class to have that Discriminator property, but if I add a property with that name, the DB which gets generated after update-database, has a column called Discriminator1.
I've tried -
modelBuilder.Entity<BaseClass>()
.Map<DerivedClass1>(m => m.Requires("Discriminator").HasValue("DerivedClass1").IsRequired())
.Map<DerivedClass2>(m => m.Requires("Discriminator").HasValue("DerivedClass2").IsRequired())
.Map<DerivedClass3>(m => m.Requires("Discriminator").HasValue("DerivedClass3").IsRequired());
But then, when I am trying to enter seed data, I get this error -
System.Data.Entity.Core.EntityCommandCompilationException: An error occurred while preparing the command definition. See the inner exception for details. ---> System.Data.Entity.Core.MappingException:
(526,10) : error 3032: Problem in mapping fragments starting at line 526:Condition member 'BaseClass.Discriminator' with a condition other than 'IsNull=False' is mapped. Either remove the condition on BaseClass.Discriminator or remove it from the mapping.
So all I want is to see the Discriminator property in C# class, without using any extra column (whose value I want to read after fetching a row from DB).
Thanks for any help.

Related

How to fetch objects, and create new objects if they do not exist?

How can I update my database rows and create new rows if they do not exist with the operations defined in my DB context? I am using the unit of work pattern in my code as described here
I am using the DefaultIfEmpty() method to create new objects if they do not exist in the database.
// this code runs every 10 sec
foreach(/* possible values for property in contract entity */)
{
var contract = unitOfWork.OptionsContractRepository
.Get(/* loop variable match */)
.DefaultIfEmpty(new OptionsContract { /* set default property values */}).Single();
// contract has a list of 'marks'
var mark = contract.OptionsMarks.Where(/* property filter */).DefaultIfEmpty(new OptionsMark { /* set default property values */}).Single();
// update some properties in 'mark'...
mark.OptionsContract = contract; // set 'contract' for the 'mark'
unitOfWork.OptionsContractRepository.Insert(contract);
}
unitOfWork.Save();
I want the code to not worry about whether the object exists in the database and just create new ones on the fly. I am getting errors when I try to save everything to the database:
System.InvalidOperationException: 'The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: Saving or accepting changes failed because more than one entity of type 'UlyssesPriceModel2.OptionsContract' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.'
How can I do this with the unit of work pattern?

How to not specify SQL expression in HasComputedColumnSql of EF Core Fluent API in DB first approach?

In previous version of EF, to specify a computed column we would write:
modelBuilder
.Entity<Type>()
.Property(x => x.ComuptedProperty)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
This would make sense, because the SQL expression for the computed column is written once in database.
However, after migrating to EF Core, we realized that the syntax should be changed into:
modelBuilder
.Entity<Type>()
.Property(x => x.ComuptedProperty)
.HasComputedColumnSql("SQL Expression should be duplicated here");
This makes sense when we go code first. Because EF Core uses this SQL expression while creating the table.
However, for DB first scenarios this doesn't make sense at all. We tried to leave this parameter empty, and it throws an exception complaining:
The string argument 'sql' cannot be empty
Now things get even worse when you want to have a data access generator. How can we neglect this parameter?
Indeed when using HasComputedColumnSql you must specfiy the SQL query that will be used for the computed column when generating SQL Script for the associated table. Like you say, this is useful only for Code First approach.
In Database First approach, you can use one of the following methods frol PropertyBuilder<TProperty> type (description are from XML documentaiton of those methods):
ValueGeneratedOnAdd(): Configures a property to have a value generated only when saving a new entity,unless a non-null, non-temporary value has been set, in which case the set value will be saved instead. The value may be generated by a client-side value generator or may be generated by the database as part of saving the entity.
ValueGeneratedOnAddOrUpdate(): Configures a property to have a value generated when saving a new or existing entity.
ValueGeneratedOnUpdate(): Configures a property to have a value generated when saving an existing entity.
In your case because it's a computed column then the value maybe generated when adding and saving the data so you must use ValueGeneratedOnAddOrUpdate() method. Again EF documentation say that :
This just lets EF know that values are generated for added or updated entities, it does not guarantee that EF will setup the actual mechanism to generate values.

Error 3004: No mapping specified for properties Invoice.IdEx in Set

I get this compilation error :
Error 3004: Problem in mapping fragments :No mapping specified for properties Invoice.IdEx in Set Invoices.IdEx An Entity with Key (PK) will not round-trip when: Entity is type [Models.Invoice] C:\Workspace\PrDomainModel\EntityFramework\Model.edmx DomainModel
I try to delete Invoice.IdEx in my edmx (this field is no longer present in my DB). But after that my ModelGenerator is empty even if I run custom tool.
IdEx is a FK but there is no link anymore.

Creating entity in database with unmapped property

The entity model I'm working on is structured with inheritence as per:
public abstract class Line {}
public class WooLine : Line{
public bool wooProperty{ get; set; }
}
public class BooLine : Line
These are both stored in the database in the table Line. And in the database the column wooProperty is NOT NULL and default value (0).
These are maintained in a web app written with Knockout & Breeze. When working with BooLine trying to create a new entity, it throws an exception that I can't insert NULL into column wooProperty.
I set up a profile to trace the query, and it appears that since it's mapped to the Line table, during the Insert EntityFramework reads up all the properties and tries to actually insert NULL into the wooProperty, since it's not present in the Boo model. I'm moderately upset that EF is actively trying to insert NULL to a property I'm not working with...
Anyway. I can't move the wooProperty to the Line model - it belongs in the WooLine model. I'm hoping to solve it by either modifying the metadata in Breeze or forcing the wooProperty onto the saveChanges data. But I can't get breeze to recognize the property in the metadata. I've tried to run
metadataStore.registerEntityTypeCtor(
'BooLine', function () {
this.wooProperty = false;
});
Which almost works - but Breeze maps it as __unmapped value and as such isn't recognized after being recieved by EntityFramework.
I also started playing around with overriding the EFContextProvider and overriding BeforeSaveEntity. Entity is ReadOnly of type BooLine, and I can clearly see WooProperty in the UnmappedProperties, but I have no idea where to go from there... Any ideas?
TLDR in a way; Want to 'trick' entity framework into thinking an unmapped value is mapped when creating an entity.
To summarize my comments I would recommend one of the following:
make your model use TPT inheritance so there is no wooProperty column in the Line table, but in the inherited WooLine table
change your wooProperty column to be nullable and mark the wooProperty property in your entity class as [Required] and let EF take care of reading only "valid WooLines" - this should work if there is also a valid discriminator column for EF to use

How to create Discriminator column in Database First

I have a Database First approach to my application and Entity Framework. I have a base class that many other classes inherit. I am trying to save the class to my EF database, however, I keep getting an error that there is no Discriminator column.
System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'.
Since I am using Database First, how do I manually create this column in my table? I cannot seem to find the datatype of it anywhere.
The entity framework would try to check for the column in all of the derived classes (isn't that what inheritance is all about?). You can try adding [NotMapped] attribute to your child classes.
[NotMapped]
public class ChildClass : ParentClass {
// other stuff here
}
This would minimize your problem. This attribute tells Entity framework which of the properties (if applied to fields) or classes do not need to be mapped. Read more about it: https://msdn.microsoft.com/en-us/data/jj591583.aspx?f=255&MSPPError=-2147217396#NotMapped

Categories

Resources