How to update many databases when we update any table? - c#

I am creating a C# Windows application which is based on a medical inventory.In this application I have mainly three forms as PurchaseDetail,SalesDetail,and StockDetail.
Now I want a functionality in which if I insert or modify the records in PurchaseDetail,or SalesDetail, the data in the StockDetail should also be modified.(for example if i insert some quantity of medicines in PurchaseDetail then Quantity in StockDetail should also modified and same as for SalesDetail )
Columns in PurchaseDetail:
Id(Primary Key and auto increment int),BatchNumber,MedicineName,ManufacturingDate,ExpiryDate,Rate,MRP,Tax,Discount,Quantity
Columns in SalesDetail:
Id(PrimaryKey and auto increment int),BillNumber,CustomerName,BatchNumber,Quantity,Rate,SalesDate
Columns in StockDetail:
Id(Primary Key and auto increment int),ProductId,ProductName,OpeningStock,ClosingStock,PurchaseQty,DispenseQty,PurchaseReturn,DispenseReturn
Please help me.

I'm guessing that you are talking about 3 tables in one database (although the title seems to indicate otherwise).
You could use triggers to achieve what you are asking for. (Note that I gave you a tsql example in the link)
OR,
You could write a transactional procedure to perform all steps (or none) at once.

I'm assuming that you mean 'update many tables', not multiple databases.
There are at least 3 ways to do this
Database Triggers on PurchaseDetail and SalesDetail which also update StockDetail.
Wrap the inserts into PurchaseDetail or SalesDetail with Stored Procs, which also update the StockDetail accordingly
Do this from code (in your C# layer), similar to 2.

Related

Query on Identity Column on MS SQL DB

I have created table in MS SQL 2008 with one identity column(Start Value - 1 and Increment is also 1) and 4 other columns. I am accessing this DB from C# ASP.NET. Used to push data only for the non identity column. Identity column will auto increment itself.
As of now i am manually querying the column value with the remaining for columns. But I am facing problem if all the other four column values are equal i am not getting the exact value which i am looking for
Now my query is, Is there any why in C# where I can get the value of the newly created identity column whenever new record is created.
Thanks.
You can use
SCOPE_IDENTITY()
Which will returns the primary key value of the recently inserted row
The answer to your question actually lies in SQL Server. You can run:
SELECT ##identity
after your insert to get the last inserted row identity.
http://technet.microsoft.com/en-us/library/aa933167(v=sql.80).aspx
EDIT BASED ON COMMENTS:
Consider using SCOPE_IDENTITY() as referenced here:
http://technet.microsoft.com/en-us/library/aa259185(v=sql.80).aspx
In SQL terms you can output the records back if you wish it. But how you might apply this to C# is up to you. Example:
INSERT INTO TABLE_A (SOMETHING, SOMETHINGELSE, RANDOMVAL3)
OUTPUT inserted.A_ID, inserted.SOMETHING, inserted.SOMETHINGELSE, inserted.RANDOMVAL3
SELECT 'ASD','DOSD', 123
But unless you're using merge, you can't use OUTPUT to print out any values from joining tables from an INSERT. But that's another matter entirely, I think.
Also, it's hardly good practice to bounce this data between the application and the DB all the time, so I'd look to alternatives if possible.

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..

Primary key violation error in sql server 2008

I have created two threads in C# and I am calling two separate functions in parallel. Both functions read the last ID from XYZ table and insert new record with value ID+1. Here ID column is the primary key. When I execute the both functions I am getting primary key violation error. Both function having the below query:
insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name')
Seems like both functions are reading the value at a time and trying to insert with the same value.
How can I solve this problem.. ?
Let the database handle selecting the ID for you. It's obvious from your code above that what you really want is an auto-incrementing integer ID column, which the database can definitely handle doing for you. So set up your table properly and instead of your current insert statement, do this:
insert into XYZ values('Name')
If your database table is already set up I believe you can issue a statement similar to:
alter table your_table modify column you_table_id int(size) auto_increment
Finally, if none of these solutions are adequate for whatever reason (including, as you indicated in the comments section, inability to edit the table schema) then you can do as one of the other users suggested in the comments and create a synchronized method to find the next ID. You would basically just create a static method that returns an int, issue your select id statement in that static method, and use the returned result to insert your next record into the table. Since this method would not guarantee a successful insert (due to external applications ability to also insert into the same table) you would also have to catch Exceptions and retry on failure).
Set ID column to be "Identity" column. Then, you can execute your queries as:
insert into XYZ values('Name')
I think that you can't use ALTER TABLE to change column to be Identity after column is created. Use Managament Studio to set this column to be Identity. If your table has many rows, this can be a long running process, because it will actually copy your data to a new table (will perform table re-creation).
Most likely that option is disabled in your Managament Studio. In order to enable it open Tools->Options->Designers and uncheck option "Prevent saving changes that require table re-creation"...depending on your table size, you will probably have to set timeout, too. Your table will be locked during that time.
A solution for such problems is to have generate the ID using some kind of a sequence.
For example, in SQL Server you can create a sequence using the command below:
CREATE SEQUENCE Test.CountBy1
START WITH 1
INCREMENT BY 1 ;
GO
Then in C#, you can retrieve the next value out of Test and assign it to the ID before inserting it.
It sounds like you want a higher transaction isolation level or more restrictive locking.
I don't use these features too often, so hopefully somebody will suggest an edit if I'm wrong, but you want one of these:
-- specify the strictest isolation level
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
insert into XYZ values((SELECT max(ID)+1 from XYZ),'Name')
or
-- make locks exclusive so other transactions cannot access the same rows
insert into XYZ values((SELECT max(ID)+1 from XYZ WITH (XLOCK)),'Name')

Recommend usage of temp table or table variable in Entity Framework 4. Update Performance Entity framework

I need to update a bit field in a table and set this field to true for a specific list of Ids in that table.
The Ids are passed in from an external process.
I guess in pure SQL the most efficient way would be to create a temp table and populate it with the Ids, then join the main table with this and set the bit field accordingly.
I could create a SPROC to take the Ids but there could be 200 - 300,000 rows involved that need this flag set so its probably not the most efficient way. Using the IN statement has limitation wrt the amount of data that can be passed and performance.
How can I achieve the above using the Entity Framework
I guess its possible to create a SPROC to create a temp table but this would not exist from the models perspective.
Is there a way to dynamically add entities at run time. [Or is this approach just going to cause headaches].
I'm making the assumption above though that populating a temp table with 300,000 rows and doing a join would be quicker than calling a SPROC 300,000 times :)
[The Ids are Guids]
Is there another approach that I should consider.
For data volumes like 300k rows, I would forget EF. I would do this by having a table such as:
BatchId RowId
Where RowId is the PK of the row we want to update, and BatchId just refers to this "run" of 300k rows (to allow multiple at once etc).
I would generate a new BatchId (this could be anything unique -Guid leaps to mind), and use SqlBulkCopy to insert te records onto this table, i.e.
100034 17
100034 22
...
100034 134556
I would then use a simgle sproc to do the join and update (and delete the batch from the table).
SqlBulkCopy is the fastest way of getting this volume of data to the server; you won't drown in round-trips. EF is object-oriented : nice for lots of scenarios - but not this one.
I'm assigning Marcs response as the answer but I'd just like to give a little detail on how we implemented the requirement.
Marc response helped greatly in the formulation of our solution.
We had to deal with an aim/guideline to keep within the Entity Framework while not utilizing SPROCS and although our solution may not suit others it has worked for us
We created a Item table in the Database with BatchId [uniqueidentifier] and ItemId varchar columns.
This table was added to the EF model so we did not use temporary tables.
On upload of these Ids this table is populated with the Ids [Inserts are quick enough we find using EF]
We then use context.ExecuteStoreCommand to run the SQL to do join the item table and the main table and update the bit field in the main table for records that exist for the batch Id created specifically for that session.
We finally clear this table for that batchId.
We have the performance, keeping within our no SPROC goal. [Which not of us agree with :) but its a democracy]
Our exact requirements are a little more complex but insofar as needing good update performance using the Entity framework given our specific restrictions it works fine.
Liam

Linq to Entities or EF version of Set Identity_Insert <TableName> ON

Similar to This Question using linq to SQL, but I don't want to just execute SQL commands from the code. I could write a stored procedure.
I am writing the year rollover functions for an application and I would like to be able to make sure that the next year uses the next available PK slot so that I can use math to go back between years.
The user wants a roll back function also, so there is the distinct possibility of gaps since a year will be deleted at that point.
This also begs the question of whether relying on pk values to be sequential is too brittle...
Question: Is there a way to short-circuit the way EF inserts records and specify the primary key I would like inserted with the record?
I would say your design is absolutely too brittle. The PK really should not be an application concern except for retrieving a given record, imo.
That said, if you must do it that way, you can set the StoreGeneratedPattern flag to "None" and then insert whatever PK you want to from the app, but of course if hte DB itself is using an autoincrementing key of some kind (e.g. IDENTITY), then you'll still break.
Update
Why do the requirements to a) have one row per year and b) roll back each year translate into anything at all for the PK? Why not just have a 'year' column (set to UNIQUE or not) which can be used in your query?

Categories

Resources