Entity Framework Decimal Truncation Issue - c#

The project I'm working on uses Entity Framework 6.0 Code-First.
One of my co-workers, due to his lack of experience with EF, manually changed the field type of a field on the database to being decimal(28,10), instead of doing it the correct way in the OnModelCreating method of DbContext. Entity Framework allowed him to do so, never throwing an error upon any future migrations.
Last week, another co-worker was running into a problem with a process that clones records from that table, where the decimal values in the new records were being truncated to 2 decimal places (with no rounding occurring).
The code for that cloning resembles the following (using the Repository pattern on top of EF):
public void CloneAccounts(List<Account> accounts, int newQuarterID)
{
var newAccounts = new List<Account>();
accounts.ForEach(account =>
{
var clonedAccount = new Account
{
QuarterID = newQuarterID
AccountName = account.AccountName,
AccountNumber = account.AccountNumber,
Amount = account.Amount
};
newAccounts.Add(clonedAccount);
});
AccountRepository.AddMany(newAccounts);
AccountRepository.Save();
}
When I pointed out, as a side-point, that the declaration of the Amount field being decimal(28,10) should really be in OnModelCreating, he went ahead and did that, and added a migration. Doing that, interestingly enough, ended up solving the issue with the code above.
My question is two-fold:
Why did that issue not affect the creation of the original records as well, and only upon cloning?
Why did adding that line in OnModelCreating fix it?
Thanks!

If you didn't originally have any precision set, the default convention for code-first is to create decimal columns with precision of 18 and scale of 2 (so only two decimal places). I think it's possible the records had originally been truncated in the first place.
Also, by default, the SQL Server provider's SQL generator sets SqlParameter.Scale property to the scale defined in the model, unless you had TruncateDecimalsToScale set to false, which would affect database updates and inserts. I'm not sure how those records with additional decimal places ended up in the database, though.

When using codeFirst with EF it creates the model in code (C# or VB), then it replicates the model to your DB.
To answer your questions I could say that:
The issue did't affect at first because when you created your model all the changes were made directly to your DB, then you had your tables exactly the same as in the model.
Remember that Entity Framework is an ORM (Object Relational Mapper) it creates, for you and with little effort, a set of entities (classes) based on a domain model -- this domain model can exists it three different flavours: code-first, model-first, and database-first.
Code-first means that you start your project by creating a set of classes (aKa Entities) which will represent your relational model in your data base. (your source will be your classes and the target your database).
Model-first means that you start your project by using a visual tool, basically drag and drop, connecting points and so on, which lets you create a model which will represent your relational model in your data base. (your source will be your model and the target your database).
Database-first means that you start your project by selecting the model from a data source (usually a database), this approach will create for you a set of classes (Entities) in your visual studio project. (your source will be your database and the target your code).
So, whatever change you make in any of the above scenarios must be replicated from source to target via Entity Framework.
What happened here was a mistake from your co-worker, who made a change directly in your database, but it must had been done from your EF project (code first).
When you invoked ClonneAccounts EF made all the magic (connect to DB, execute a query, gets data, cast it to your entity classes, and then retrieve them or visceversa) --> this is when your app crashed because of an InvalidCastException.
EF does not check consistency, scheme or structure of your tables every time you invoke ClonneAccounts, it just retrieves data between Entities and Database and insert/update data. If you want to update/check consistency and replicate changes you have to do it manually. That is why until you fixed your model in the "code side" and ran the tool it replicated all changes to your db.
Hope it helps

Related

Multiple databases with slightly changing models. How do I allow `EF` to work with different database structures at run-time?

I am working with EF6, MSSQL, Oracle, .NET4.5 on a system that is used globally across company (many departments) to query different databases that belong to our department, that have mostly same EF model, some databases are Oracle and some are Microsoft SQL, some are development or uat, some are logs.
I am using different EF models for Oracle and for MSSQL databases.
One requirement is to switch between databases at run time, and this is easy,
public AggregatorEntities(string connectionString)
: base(connectionString)
{
}
however it does have side effects - many databases (dev, uat, dr, logs,...) are out of sync from what Live is (model is generated from Live), which results in errors when querying those databases.
Management knows about situation and they are ok for devs that work on some specific database to do changes to global querying system that would allow testers and uat to query the data. However they want changes they have to do to take minimum time to do this - as it is additional cost to each project that involves database changes. I will basically need to build a 'can handle all' resilient system, that when one changes database in EF will do something to accommodate to specific database.
There are different failure scenarios:
1. Name of column on table is the same but Type is different in entity
2. No column on table but there is one on entity in EF
3. Additional columns on table that are not on EF
4. Additional tables in database that are not in EF model
5. No table in database but there is entity in EF model.
I have done some thinking and this question is broad and might get closed for same reason. However I am not sure if it is worth splitting the question into each scenario, as it depends on the answer. The way I understand if single answer can answer all points then no need to split, however if each situation has different 'cure' then question should be split for that part only, but without answer no way to know.... (catch 22).
Only option I see ATM is to generate it's own model for each mirroring database, but then I end up with 50+ models.
How do I allow EF to work with different database structures at run-time?
This now officially cannot be done in a proper manner.
However end result of being able to switch between different databases with similar structures still can be achieved (for those without morals). Part with removing columns can used.
Solution is to have all inclusive EF model that is generated from database that has all the tables and all the columns (that are in any database think like logical OR of everything). Then model with all entities that have all properties from all db environments can be removed specific to environment that is queried at runtime in mechanism described here. This does not cover cases where type of column changes.
Hope this saves you some time as it took 2 weeks from mine...

Database codefirst entity framework

I'm working on an ASP.NET project. I migrated my database named "youbay" with
reverse engineering. It worked. My database contains tables (picture, user, product...) but when I try to change something on the code and then update my database it with code first other tables are then created named youbay.picture,youbay.user...
What do you concretely mean with RE? Creating ASP.NET Models by guessing the mapped .NET types of the table scheme? Maybe your db-structures are a bit different from the ones EF would genereate itself, so that EF will see a conflict. Or EF keep track of the changes itself, so he isn't touching the tables because he won't recognize that he created them.
Whatever happened, it seems like your way of migrating was not very clean. You should tell EF use an existing database like explained here. This will prevent conflicts and also save work/time, because EF will automatically generate your models based of the database-scheme. So no RE is needed.

Is it possible to use Entity Framework and keep object relations in the code and out of the database

I'm having a hard time just defining my situation so please be patient. Either I have a situation that no one blogs about, or I've created a problem in my mind by lack of understanding the concepts.
I have a database which is something of a mess and the DB owner wants to keep it that way. By mess I mean it is not normalized and no relationships defined although they do exist...
I want to use EF, and I want to optimize my code by reducing database calls.
As a simplified example I have two tables with no relationships set like so:
Table: Human
HumanId, HumanName, FavoriteFoodId, LeastFavoriteFoodId, LastFoodEatenId
Table: Food
FoodId, FoodName, FoodProperty1, FoodProperty2
I want to write a single EF database call that will return a human and a full object for each related food item.
First, is it possible to do this?
Second, how?
Boring background information: A super sql developer has written a query that returns 21 tables in 20 milliseconds which contain a total of 1401 columns. This is being turned into an xml document for our front end developer to bind to. I want to change our technique to use objects and thus reduce the amount of hand coding and mapping from fields to xml (not to mention the handling of nulls vs empty strings etc) and create a type safe compile time environment. Unfortunately we are not allowed to change the database or add relationships...
If I understand you correct, it's better for you to use Entity Framework Code First Approach:
You can define your objects (entities) Human and Food
Make relations between them in code even if they don't have foreign keys in DB
Query them usinq linq-to-sql
And yes, you can select all related information in one call.
You can define the relationships in the code with Entity Framework using Fluent API. In your case you might be able to define your entities manually, or use a tool to reverse engineer your EF model from an existing database. There is some support for this built in to Visual Studio, and there are VS extensions like EF Power Tools that offer this capability.
As for making a single call to the database with EF, you would probably need to create a stored procedure or a view that returns all of the information you need. Using the standard setup with lazy-loading enabled, EF will make calls to the database and populate the data as needed.

Continuous delivery and database schema changes with entity framework

We want to progress towards being able to do continuous delivery of of our application into production. We currently deploy to azure and use table/blob storage and have a azure sql database, which we access with the entity.
As the database schema changes we want to be able to automatically apply the schema changes to the production database, but as this will happen whilst the application is live and the code changes are being deployed to many nodes at the same time we are not sure what the correct approach is.
After some reading it seems (and this makes sense) that the application needs to be tolerant of the 2 different database schema versions, so that it doesn't matter if its an old version of the code or a new version of the code which sees the database, however I'm not sure what the best way to approach handling this in the application is, using the entity framework.
Should we have versioned instances of the EF generated classes in the code which know how to access a specific version of the schema? What happens when the schema is updated and an old version of the code is running against the database?
Our entity framework classes are mapped to views in specific schemas in the db and nothing is mapped to the underlying tables, so potentially this could allow us to create v1 views which the old code uses and v2 views which the new code uses, but maintaining this feels like it would be a bit of a nightmare (its already enough of a pain simply maintaining the EF mappings to views rather than tables)
So what are best practices in this area? What do others do to solve this problem?
Whether you use EF or not, maintaining the code's ability to work with 2 consecutive versions of the database is a good (and perhaps the only viable) approach here.
Here are some ways we handle specific types of migrations:
When adding a column, we can typically just add the column (with a default constraint if non-nullable) and not worry about the code. EF will never issue a "SELECT *", so it will be able to continue to function properly while ignoring the new column. Similarly, adding a table is easy.
When removing a column or table, simply keep that column around 1 version longer than you would have otherwise.
For more complex migrations (e. g. completely changing the structure for a table or segment of the data model), deploy the new model alongside backwards-compatibility views (or tables with triggers to keep them in-sync), which will live as long as does the code that references them. As you say, this can a lot of work depending on the complexity of the migration, but it sounds like you are already well-positioned to do this because your EF entities point to views anyway. On the other hand, the benefit of this work is that you have more time to do the code migration. If you have a large codebase, this could be really beneficial in allowing you to migrate the data model to fit the needs of new features while still supporting old features without major code changes.
As a side-note, the difficulty of data migration often makes us push developing a finalized data model as far back as possible in the development schedule. With EF, you can write and test a lot of code before the data model is finalized (we use code-first to generate a sample SQLExpress database in a unit tests, even though our production database is not maintained by code-first). That way, we make fewer incremental changes to the production data model once a new feature is released.

View using same type as Table

I have a table that used throughout an app by Entity. I have a view that returns an identical column set, but is actually a union on itself to try to work around some bad normalization (The app is large and partially out of my hands, this part is unavoidable).
Is it possible to have Entity 4 treat a view that is exactly like a table as the same type, so that I can use this view to populate a collection of the same type? This question seems to indicate it is possible in nhibernatem but I can't find anything like it for entity. It would be an extra bonus of the navigation properties could still be used to Include(), but this is not necessary (I can always manually join).
Since EF works on mappings from objects to database entities this is not directly possible. What you need is something like changing the queried database entity dynamically, and AFAIK this is not possible without manually changing the object context.
For sure the EF runtime won't care as long as it can treat the view as if it was completely separate table. The two possible challenges that I forsee are:
Tooling: Our wizard does allow you to select views when doing reverse engineering (i.e. database-first). Definitively if you can use 'code first against an existing database' you can just pretend that the view is just a table, but you won't get any help scripting the database creation or migrations.
Updates: in general you can perform updates for a view setting up store procedure mapping (which is available in the EF Designer from v1 or in Code First starting in EF6). You might also be able to make your view updatable directly or using instead off triggers (see "Updatable Views" here for more details). If I remember correctly the SQL generated by EF to retrieve database generated values (e.g. for identity columns) is not compatible in some cases with instead-off triggers. Yet another alternative is to have your application treat the view as read-only and perform all updates through the actual table, which you would map as a separate entity. Keep in in mind that in-memory entities for the view and the original table will not be kept in sync.
Hope this helps!

Categories

Resources