MVC : Insert data to two tables - c#

I have two tables wherein i want to insert the data to the first one (MASTER) and the other table would copy some of the data from the Master table..
Here is my representation:
I want the Ven_ID to also be reflected in my Workflow table Workflow_ReqID automatically.
I know this is possible but can someone give me the directions ?

You can have a trigger/procedure at database level which will insert data into your second table. It depends if this table is updated anywhere else.

There are two ways to go about it :
Use SQL Server AFTER INSERT Trigger. You can find plenty of resources off the internet on how to create a trigger and how to declare its definition.
Another way to do it is through entity framework (I see you have tagged entityframework)
I will explain how you can use entity framework
Let's say you have the entity representing the WorkFlow table as WorkFlow and the table representing Ven (may be vendor) as Vendor.
Since you are having required foreign key in the WorkFlow table of the Vendor primary key, you must have a backing stub for that i.e. your WorkFlow table must have a virtual navigational property of type Vendor i.e.
public class WorkFlow
{
//other properties
public virtual Vendor Vendor{get;set;}
}
you just have to create WorkFlow object and the Vendor object (either create a new or retreive from db) and just assign it to the workflow object i.e.
WorkFlowObj.Vendor = objVendor
and EntityFramework will take care of rest.
I would prefer this way.
Though using triggers is not bad, but only problem with them is when you have to deploy, you must also deploy them triggers and every time you make changes to them, you must take care of them too.

If you want Ven_ID and Workflow_ReqID to be same get the Vent_ID in the output parameter in store procedure and pass it to the second table insert statement.

Get last inserted id using SCOPE_IDENTITY() after insertion and add it to workflow table. To save db trip you can use sproc for that.

Related

Best Practice with classes and the database

I would like to learn more about the appropriate way to use classes when using a database. Here is the example of what I think is ok.(Using C# and SQL Server if curious)
I Have a table called "Features" and most of the columns in it hold IDs(Foreign keys). To load that table into the application, I create a "DBFeatures" class to hold all the columns. Next I should have a regular "Features" class that has the actual values of all properties in "DBFeatures" class. "Features" class would have a method that opens a connection to the database to grab all the right values with the given IDs. Then The "Features" class can be used as is.
The same would go in reverse, I create an object of "Features", then it converts it into a "DBFeatures" class which gets passed to the database when INSERTING.
Is this the right way to go about this? What other options would be better? The only other option is just have one class, "DBFeature" class, and when I create an object of that class, each time a property is set or gets, it would have to access the database to get the value by providing an ID.
EDIT
I'll be using the data for forms. Most of the tables will be read only which will be stored into a list of objects which can then be used with Controls(like the data source of a combobox). Also I want to be able to load user input into a class that would be outputed to a table in the database.
A lot of planning on how to do something depends on your implementation which you are not providing. What are you planning to do with your objects? Is it for a report? Do you need to manipulate the values?
I'm going to assume you are going to be manipulating the data in which case you should have a class that opens the database and loads it into classes that represent it.
The class can have properties that correspond to the columns and then you can have a list of the class to represent the rows.
This is just one example of how to do it but its impossible to say without knowing what your intent is and having more details.
It looks like you need ORM like Entity Framework.

Entity Framework, database wide Guid table, insert order

We have a synchronization framework that uses a global SyncEntity table to keep track of which entities have been updated at what time, meaning we have a global table with a structure something like this:
<dbo.SyncEntity>
ID int
EntityType int
EntityGuid uniqueidentifier
The EntityType is an enum that corresponds to the specific entity so that we know in which table to look for this entity.
All our tables have an ID (PK) and a GUID.
I have created a Foreign Key constraint from the different Entity tables and to the EntityGuid in the SyncEntity table.
This works perfect for existing data however when we use EntityFramework to insert new data it doesnt insert the data in the "correct" order resulting in an error because the SyncEntity with the required EntityGuid is not yet inserted.
I guess we could add a property SyncEntity on all of our entities however i really dont want to pollute our domain model with that property.
So my question, is there anyway to ensure that specific Entity types are inserted as the first entities?
Or is there anyway to map the relation from Guid (on the specific Entity) to EntityGuid (on SyncEntity) without a navigation property.
I see two ways you could potentially alleviate this issue.
First, you could use domain events to recognize that a new entity has been created and raise an event, passing in the entity itself as a parameter and then allow that event to create a new SyncEntity insert it and then save it. This will populate your ID and then you can assign it to the new entity creating the relationship.
Second, you could override the SaveChanges method of the DbContext to look at added entities and then create a new record for each of them, then assign your new SyncEntity Ids to the entity.
WHy would you bother EF with something like that?
Have the SyncEntity entry created by a trigger on the tables. Finished. EF does not have to bother with it.
And it is save for direct SQL usage, too.
EF is a good tool - though only a very very mediocre ORM. But it is not a solution for everything. DB internal logic, like a logging table, should be handled in the database.

DbContext with read-only set properties

I was reading this article http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-2-connections-and-models.aspx and was trying to figure out how to create private setters (the section in the article DbContext with read-only set properties is right before the summary). How would you create private setters? I was playing around with different methods but nothing seemed to work. I am doing this because I need to group the original table based on a query I have because the original table is a heap and I need a primary key for the entity. So anytime a client asks for this table it is already grouped. Not even sure if this is the correct way to do that. Thanks.
EDIT: sorry for being vague. I am doing code first. For example there exists a SQL Table with JobNbr, Qty and Date and I need to group by JobNumber, sum on Qty and take the oldest expiration date, and that will be my entity since this table has no primary key. The way I am doing it now gives me the error below from a method I created in the DbContext class. I do have a EntityTypeConfiguration class. Do I do this in that class?
EDIT: : you might be wondering why I am doing this. Basically I need to get data from the heap and save it in another database. My original approach was database.SqlQuery() to get grouped rows from the heap, but sometimes I have too many parameters for execute_sql. So I decided to create an entity for the grouped query without tracking changes (since all I am doing is reading from the table and saving to another DB). See my post here with the issue I am having https://stackoverflow.com/questions/22106030/entity-framework-6-this-database-sqlquery-character-limitation-with-sp-executes. The only way I know to get around it is to create an entity (even though in this case the entity is a query and not a table).
The entity or complex type
' cannot be
constructed in a LINQ to Entities query.

Entity Framework doesn't update value which is modified by a trigger

My table Sections (SQL Server) has ID as a primary key (int, identity) and SortIndex column (int) for sorting purposes.
The database has a trigger which sets SortIndex := ID at each INSERT. Obviously I want to change the sorting index later, by swapping the values for two rows.
I access the data using Entity Framework, all with MVC3 web application.
The problem is, Entity Framework doesn't update the value of SortIndex after I insert a new object into the table. It also caches all the data, so the following call to get all objects from this table will also give wrong SortIndex value for this object.
I tried changing StoreGeneratedPattern for this column in EDMX. This seems to be great and elegant but doesn't solve the problem.
If I set to Identity, it causes EF to properly update the value, but it becomes read only (exception thrown when trying to change). Setting it to Computed is similar, but instead of exception being thrown the values are just not written to the DB.
I can recreate the EF object every time if I need to use it after inserting an object, just by doing:
DatabaseEntities db = new DatabaseEntities()
But it seems like ugly workaround for me.
What's a solution to this problem?
Obviously something, what doesn't require me to do some action after every insert (and take a risk that it's forgotten and unnoticed) is preferred.
In short StoreGeneratedPattern means: the value is handled by the store and your application will never modify it. In such case you will get store generated value automatically after you call SaveChanges.
If you don't use StoreGeneratedPattern you will not get value and you will have to force another query execution to refresh your entity. You can for example do:
objectContext.Refresh(RefreshMode.StoreWins, yourSection);
Generally situations where you need to update values in both database through triggers and application don't play very nicely with EF (and probably also other ORM tools).
I found the answer from 'Ladislav Mrnka' being exact and marked it as accepted. Here are other workarounds, which I found while trying to find some solution. However, the solution I was looking for is in general not possible.
One of possibilities is to set StoreGeneratedPattern = Computed to let EF know, this value is calculated. And then, make a Stored Procedure to actually change the value of SortIndex. Typically it would change values in two rows (swap them), to change the sorting order. This procedure along with a trigger at INSERT gives guarantee the data stays consistent in the DB. It's not possible to create new row without proper value set in SortIndex, it's not possible to make two objects have the same value (unless stored procedure has a bug) and it's not possible to manually break the value somehow, because it's not possible to edit through EF. Looks like a great solution.
It's easily possible to have stored procedures mapped to functions in EF.
The problem is, it's now fine to enter a new row and EF properly updates data in its cache, but the cache is not updated after calling the stored procedure. Still some manual updated or refresh function is needed. Otherwise the following call to get objects sorted by SortIndex will give wrong results.
Other than that, it's possible to set MergeOption = MergeOption.OverwriteChanges for several entities, which causes EF to update data from the DB somewhat better. With this being done, it's possible to reread the object after inserting it or calling stored procedure and it will get refreshed. However, reading a collection of objects with db.Section.OrderBy(o => o.SortIndex) will still return cached results with wrong sorting order.
If anyone is interested, it's possible to make MergeOption default to something else by adding EF partial class and then partial method OnContextCreated, like here:
public partial class DatabaseEntities
{
partial void OnContextCreated()
{
Subsection.MergeOption = MergeOption.OverwriteChanges;
Section.MergeOption = MergeOption.OverwriteChanges;
Function.MergeOption = MergeOption.OverwriteChanges;
}
}
Do you know if you'll work with that column again in the same request?
I would use the context per request scenario, which usually gets you out of many problem, because a new EF context is created with every request, so you have a fresh data once per request.
With long lived context, there can grow incosistencies as you described.
Anyways the StoreGeneratedPattern setted to computed should be right. But it updates itself only when you're storing the actual entity. It's not getting updated by inserting or updating any other entity.
from http://msdn.microsoft.com/en-us/library/dd296755(v=vs.90).aspx
If you create a new entity or change an existing entity, the values of properties with StoreGeneratedPattern set to Computed are retrieved from the server when you call the SaveChanges method in your application.
If you assign a value to a property with StoreGeneratedPattern set to Computed in your application, the value will be overwritten with the server-generated value when you call the SaveChanges method.
We're using the computed value option for SQL sequenced GUID, and it's working OK.
I had a similar situation with a Sql Server Quote table with a varchar QuoteNumber column that is a non-primary unique key whose value is generated by an after-insert trigger. The trigger is used because the generated value is derived by fetching data from a foreign key table. Sql Server schema identity declarations do not allow you to pull information from other tables.
I'd like EF to treat this varchar column like an identity and do nothing to it on update and reread it after insert. EF will do so if there is a .HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity) property to a non-identity column in the code it generates to configure the Entity like so (scroll right):
public QuoteConfiguration(string schema)
{
ToTable("Quote", schema);
HasKey(x => x.ID);
Property(x => x.ID).HasColumnName(#"ID").HasColumnType("int").IsRequired().HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
Property(x => x.QuoteNumber).HasColumnName(#"Quote_Number").HasColumnType("varchar").IsOptional().IsUnicode(false).HasMaxLength(64).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
}
My EF model is code first and generated by Simon Hughes' EntityFramework Reverse POCO Generator. At first, I could not figure out how to make the generator add this property to a column that is not declared as an identity in Sql Server.
Rereading the entire Quote entity after insert did not retrieve the auto-generated QuoteNumber. Then I discovered that re-reading just the QuoteNumber column after insert defeated the entity cache. But, I felt dirty doing it.
Finally, I worked with Simon Hughes to discover how to get his EF Reverse POCO to do it for me. You just extend the UpdateColumn function in your *.tt file like so:
Settings.UpdateColumn = (Column column, Table table) =>
{
if (table.Name.Equals("Quote", StringComparison.InvariantCultureIgnoreCase)
&& column.Name.Equals("Quote_Number", StringComparison.InvariantCultureIgnoreCase))
{
column.IsStoreGenerated = true;
}
}

Entity Framework: Mapping sproc results to existing EF Entity

I am trying to use EF with an existing DB. I brought in a Client table into my data model and let EF create a Client entity. I have a sproc, GetClientSearch, that only returns 5 out of the 15 columns from the Client table becuase that is all that is needed for that call.
Here's what I've done so far:
Added the sproc to Function Imports and set the proc to map to the Client entity.
When I execute the proc through the Context, I get "The data reader is incompatible with the specified 'GAINABSModel.Client'. A member of the type, 'MiddleInitial', does not have a corresponding column in the data reader with the same name." exception. (MiddleInitial is not one of the columns returned in the proc)
I know that I can create a new entity that maps to the proc, but I don't want to do that for every proc I have to import into my model.
Given that the DB is currently in use in production, changing stored procs to map to my current entities may not be an option.
Currently using EF 4 and VS 2010.
So, is there a way to map the results of the sproc to the Client entity, even though the columns returned are not 1:1 with the properties of the EF entity?
Yep, one of my many pain points in EF.
If you can't modify the SP's, your best bet might be to create "wrapper" SP's on top of the existing SP's.
In other words, EF-serving SP's that call into the existing ones, and return NULL for the columns you don't need, but are required for the entity.
Of course the better option would be to create the entities properly.
Another option is to use ObjectContext.Translate<T>, which basically performs a L-R between the SPROC results and the entity you supply.
If the result set doesn't contain the field, then the property on the object will be null.
Which is probably what you want.
Am running into the same Issues. Suppose i have UserEntity created out of the User Table and have 3 procedures.
AuthenticateUser - returns 4 columns from the user table after authentication
RetriveUser - Returns 10 columns from the user table
GetUserName - return UserID and UserName only for dropdown purpose.
If we create different entities for each of the different SP. It would result in bad design because of duplication.
I have no other way of using same entity for all these SP's.
Overall, i don't recommend entity framework atleast for legacy applications in production.(where you can not update your Sp's also.)

Categories