Creating entity in database with unmapped property - c#

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

Related

Is there a way to ALWAYS convert string data member in Entity Model to char(n)?

Application has multiple tables - entity model classes, many of them have string data member and respective column type is char[n].
While debugging I found that Entity Framework Core default converts string to "nchar(n)" type. Since actual db column type is char(n), indices are not working properly and there is a performance hit.
Is there a way to change this default behavior (convert string to nchar(n))?
I don't want to manually go in each entity model class change like this,
property.HasColumnType("char").HasMaxLength(length).IsFixedLength();

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

Entity Framework 6.1 explicit Discriminator column

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.

Invalid object name 'dbo.TableName' when retrieving data from generated table

I'm using entity framework code first to create my tables. Please note - create the tables, not the DB, since I'm working on a hosted environment and I don't have a user that is allowed to create db's.
Committing a DB update works fine, but retrieving data gives the exception:
Exception Details: System.Data.SqlClient.SqlException: Invalid object name 'dbo.EventHosts'.
I've read that it happens because I'm not using EF Code First to create the DB. That's fine, but how do I elegantly solve this?
All the generated tables do not have a prefix like dbo. A solution like this doesn't work, and isn't elegant at all:
[Table("EventHosts", Schema = "")]
Ok, for me issue was that I had a table called dbo.UserState and in C# EF was trying to access dbo.UserStates because of pluralization.
The solution was to put Table attribute above class and specify the exact table name:
[Table("UserState")]
public class UserState
{
[Key]
public int UserId { get; set; }
}
To answer your first question: use the schema created for you by your hosting provider.
To answer your second question: No there is currently no direct way to change the default schema globally because you cannot modify existing conventions or create new conventions. You can try to hack it.
For example you can override OnModelCreating and use reflection to get all DbSet<> properties declared in your context. Than you can just use simple loop on these properties and create ToTable mapping call with name of the property as table name and your custom schema. It will require some playing with reflection to make this work.
Alternatively you can try to do some reusable approach by implementing custom conventions. You can find many different articles about using your own conventions with EF. Some examples:
Custom Conventions in Entity Framework Code First v 4.1
Conventions in Entity Framework 4.1 Final
My high level untested idea is following same principle and create assembly level attribute which will be processed by the convention mechanism and applied on all your entities.
Try to set default schema name to 'dbo' in SQL SERVER.
http://msdn.microsoft.com/en-us/library/ms173423.aspx
On of the reason for this error is the table named "EventHosts" may not Exist or that table is renamed to some other name please check with that..
https://stackoverflow.com/a/12808316/3069271
I had same issue, it was pluralize problem between mapping and db.

Disabling Entity Framework's default value generation (Code First)

I have a column in the database that cannot be null, and I want to set it to have a default value in the database . The problem is that entity framework seems to create a default value itself (for example, int => 0), and completely ignores the default value constraint in the database.
Is there any way to disable this default valuing of entity framework?
I have found that you can decorate your fields with the following attribute.
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
Natively, Entity framework do not allows this. You have to do some code to it. This answer from another site seems to had solved the problem for many people.
He "hacks" it (as he told) by doing something like that:
public partial class YourEntityClass {
public YourEntityClass() {
this.PropertyNameWithDefaultValue = default(int);
}
}
Note 1 : Someone mention that it may not work in EF4
Personal note : Sorry for my english, I usually speak French.
Sometimes we need to do manually what EF doesn't do automatically for us.
In case using EF 4.1 "Code First", I usually create a separated class DbInitializer derived from IDatabaseInitializer, and in the implementation of the InitializeDatabase method, just call the
context.Database.ExecuteSqlCommand("ALTER TABLE TABLENAME ... ");
Now at the static constructor of the class derived from DbContext, just call the initializer:
Database.SetInitializer(new DbInitializer());
In this way, it's possible to specify any database DML/DDL commands to alter tables/columns just to make sure the DB is like we want.
"Computed" fields in EF are not the same as fields with default values in SQL. A computed field is one that is computed on the server and shouldn't be altered when an object is submitted. If you put a Computed tag on a field, you will get the default when you first create the object, but then you will not be able to change that field later on. So, if you get an entity from the DB make a change to a computed field and then call "saveChanges()" on your entity context, the field will not be altered in the DB.
Better to use EF defaults by setting the Default Value for the attribute in the EDMX editor.
It's a pain in the butt that the EDMX updater can't read the field defaults when there is a one to one mapping between the entity field and the database field.
You can update the EDMX model to change the default value for any column via the Properties window. However, Entity Framework doesn't seem to pickup DEFAULT constraints automatically. Not sure if there is a way to make it do that.

Categories

Resources