Column added to view not getting picked up by Entity Framework? - c#

I added a new column MyColumn to vwMyView in MyDB. MyDB has a stored procedure MySproc which returns vwMyView.* in a select statement.
When I execute MySproc, vwMyView.MyColumn is included in the result set. However, when I recreate my EF6 .edmx data model, MyColumn is not reflected in the EF vwMyView object or in MySproc_Result.
Is there a special trick I need to use so my new column MyColumn is reflected in a recreated EF6 .edmx? Is this a quirk that you encounter sometimes?

Happens sometimes, especially when the output is generated runtime as a polymorphic behavior (different result sets based on conditions)
In EF, for a result set, you may need to explictly create an output mapping. No need to delete the whole EDMX, just select the mapping (MySproc_Result) and update the result set to include the new column.
Are you creating the view inside procedure and then returning its value?
Inside the view, check if the columns are added conditionally (eg, if type=Sales, include 4 columns, if type=Mgmt, include 5 columns). The EF will pick up the 1st matching case in this condition.
Best way is to update the mapping and have the new column set as nullable, just in case some conditional makes it unavailable.

Related

Enforce Entity Framework to follow constraints defined in database

I have a table with 10 columns, in which 7 of them are not null with constraints on it.
ALTER TABLE [dbo].[MyTable]
ADD DEFAULT (1) FOR [Column1]
Now, when I am inserting 3 columns from Entity Framework like below, it is not inserting the default values into the table:
Table obj1 = new Table();
obj1.Column7 = someValue;
obj1.column8 = someValue;
obj1.column9 = someValue;
context.Entry(obj1).State = EntityState.Added;
context.SaveChanges();
Unlike my expectation, above statement is just updating 3 columns and not using the default values for the other 7 columns.
How can I enforce Entity Framework to insert default values defined by the constraint in database?
The default values as defined in your SQL Server table structure are only applied if you have an INSERT statement that leaves out those columns - e.g. doesn't provide any value (including NULL) for those columns.
EF however will always supply values for all columns as defined by the entity - e.g. it will supply NULL for any values not explicitly set. There's nothing you can do about this, as far as I know.
There are some workarounds:
you could create a stored procedure which would take only those values you want to supply, and would run a SQL INSERT statement that would leave out the columns with default values, e.g.
INSERT INTO dbo.MyTable (colA, colB, ..., colZ) -- *exclude* "Column1" here!
VALUES ( .........)
With this, SQL Server would then use the configured default values for those column that have one defined and which are not mentioned in the column list of the INSERT INTO statement
you could probably do something similar on the EF level, by specifying a second class, that would be almost identical to your current entity class - but that would leave out the columns you want to have set by SQL Server's configured default values. If you save this "slimmed down" entity, EF would create a SQL statement that would include only those columns that it knows about (in terms of the fields of that slimmed down class) and this would result basically in the same as above - an INSERT INTO statement that excludes those columns which are automatically set by a configured SQL Server default constraint

Add column to existing SQL Server table - Implications

I have an existing table in SQL Server with existing entries (over 1 million in fact).
This table gets updated, inserted and selected from on a regular basis by a front-end application. I want/need to add a datetime column e.g. M_DateModified that can be updated like so:
UPDATE Table SET M_DateModified = GETDATE()
whenever a button gets pressed on the front-end and a stored procedure gets called. This column will be added to an existing report as requested.
My problem, and answer is this. Being one of the core tables of our app, will ALTERING the table and adding an additional column break other existing queries? Obviously, you can't insert into a table without specifying all values for all columns so any existing INSERT queries will break (WHICH is a massive problem).
Any help would be much appreciated on the best solution regarding this problem.
First, as marc_s says, It should only affect SELECT * queries, and not even all of them would necessarily be affected.
Secondly, you only need to specify all non-Null fields on an INSERT, so if you make it NULL-able, you don't have to worry about that. Further, for a Created_Date-type column, it is typical to add a DEFAULT setting of =GetDate(), which will fill it in for you if it is not specified.
Thirdly, if you are still worried about impacting your existing code-base, then do the following:
Rename your table to something like "physicalTable".
Create a View with the same name that your table formely had, that does a SELECT .. FROM physicalTable, listing the columns explicitly and in the same order, but do not include the M_DateModified field in it.
Leave your code unmodified, now referencing the View, instead of directly accessing the table.
Now your code can safely interact with the table without any changes (SQL DML code cannot tell the difference between a Table and a writeable View like this).
Finally, this kind of "ModifiedDate" column is a common need and is most often handled, first by making it NULL-able, then by adding an Insert & Update trigger that sets it automatically:
UPDATE t
SET M_DateModified = GetDate()
FROM (SELECT * FROM physicalTable y JOIN inserted i ON y.PkId = i.PkId) As t
This way the application does not have to maintain the field itself. As an added bonus, neither can the application set it incorrectly or falsely (this is a common and acceptable use of triggers in SQL).
If the new column is not mandantory you have nothing to worry about. Unless you have some knuckleheads who wrote select statements with a "*" instead of column list.
Well, as long as your SELECTs are not *, those should be fine. For the INSERTs, if you give the field a default of GETDATE() and allow NULLs, you can exclude it and it will still be filled.
Depends on how your other queries are set up. If they are SELECT [Item1], [Item2], ect.... Then you won't face any issues. If it's a SELECT * FROM then you may experience some unexpected results.
Keep in mind how you want to set it up, you'll either have to set it to be nullable which could give you fits down the road, or set a default date, which could give you incorrect data for reporting, retrieval, queries, ect..

What happens when saving objects using Entity Framework?

Probably sounds like a silly question, but there is an aspect about it I would like to know:
I'm working with objects that have a Guid-property for PrimaryKeys, which gets auto-generated in the database. I am using Entity Framework, Code First. If I do a Console.WriteLine with this property before saving, the value is
00000000-0000-0000-0000-000000000000.
After using Add and SaveChanges in the context, if I do a Console.WriteLine again with the same property, I have a value:
615f98eb-4ced-422a-877f-b9caa6f2b91f
Obviously, the object in memory has been updates. But I want to know how. The Guid is genereated in the database, so what happens?
Does the Guid-property of the object simply get updated from the database through EF, or does EF reload the entire object into memory after saving it in the database?
I would like to know, because that will determine how I design NUnit-tests in the same project.
Your EF object is updated when you call domainContext.SaveChanges(); Your new Id is generated by SQL database and value of Id is return value from DB. It is same for data types int, Guid and similar.
EF does not only submit an Insert/Update statement, at the same time it does a get statement to retrieve the generated primary key. In fact it is one single query. Your entity's primary key is then updated with the retrieved one. No magic behind this.
That's also one of the reason why batch updates / inserts are not supported. Every entity has to be updated / inserted on its own.
This is a query that is being executed when inserting an entity with a computed int primary key:
insert [dbo].[TestTable]
([Name])
values ('myname' /* #0 */)
select [ID]
from [dbo].[TestTable]
where ##ROWCOUNT > 0
and [ID] = scope_identity()
As you can see, the insert statement is followed by a select statement retrieving the computed columns (in this case ID). If there are more computed columns they're all selected here.

ADO.NET entity data model generate from database and skip columns

I want to generate EDM from my database file (.mdf), but i don't want to work with all columns. How can i skip these columns from .edmx?
You can't select specific columns at the time of generation. But, if you only want to work with a subset of columns, let the EDM generate the entire table; then in the designer surface you can select the columns you don't need and hit delete to remove them from the model.
One note is that if your database has certain constraints, such as non-nullable columns with no default value, an exception will be thrown if you try to add or update entities without those columns in your model.
You have to do this manually.
Obviously you can map tables as show here, but then you have to go through and manually remove columns. At least this is what I have been told.

How to insert to table with one-to-one relationship via dataset

I use asp.net 4 and DataSets for accessing the database. There are two tables with one-to-one relationship in the database. It means that both tables have the same column as a primary key (say Id), and one of tables has #identity on this column set.
So in general if we want to insert, we insert first into the first table, than insert into the second table with id.table2 = id of the corresponding record in table1.
I can imagine how to achieve this using stored procedure (we would insert into the first table and have id as an out parameter and then insert into the second table using this id, btw all inside one transaction).
But is there a way to do it without using a stored procedure? May be DataSets \ DataAdapters have such functionality built in?
Would appreciate any help.
Today it is so quiet here... Ok if anybody is also looking for such a solution, I've found a way to do it.
So our main problem is to get the id of the newly created record in the first table. If we're able to do that, after that we simply supply it to the next method which creates a corresponding record in the second table.
I used a DataSet Designer in order to enjoy the code autogeneration feature of the VS. Let's call the first table TripSets. In DataSet Designer right click on the TripSetsTableAdapter, then Properties. Expand InsertCommand properties group. Here we need to do two things.
First we add a new parameter into the collection of parameters using the Parameters Collection Editor. Set ParameterName = #TripId, DbType = Int32 (or whatever you need), Direction = Output.
Second we modify the CommandText (using Query Builder for convenience). Add to the end of the command another one after a semicolon like that:
(...);
SELECT #TripId = SCOPE_IDENTITY()
So you will get something like this statement:
INSERT INTO TripSets
(Date, UserId)
VALUES
(#Date,#UserId);
SELECT #TripId = SCOPE_IDENTITY()
Perhaps you will get a parser error warning, but you can just ignore it. Having this configured now we are able to use in our Business logic code as follows:
int tripId;
int result = tripSetsTableAdapter.Insert(tripDate, userId, out tripId);
// Here comes the insert method into the second table
tripSetTripSearchTableAdapter.Insert(tripId, amountPersons);
Probably you will want to synchronize this operations somehow (e.g. using TransactionScope) but it is completely up to you.

Categories

Resources