Table schema changes sometimes - delphi

We use SQL Server and ADO in Delphi and we are creating temporary tables for use with a report program.
The program flow is like this :
Create a table with a SQL query "create table"
Write data in table.
Drop table via SQL query.
It usually works, but some customers regularly complain that "drop table" fails with error "invalid object name".
I could get remote access to the customers database, and I saw following :
the table X is shown in the table listing (by Delphi)
in Delphi, the table cannot be opened or deleted.
the table schema is "Server\1" instead of "dbo"!
How could the table schema of this table change, and how should I handle this issue? Why does it work sometimes, and sometimes not?

I would suggest using temporary tables and keeping all related code in SQL.
IF OBJECT_ID('tempdb..#YourTable') IS NOT NULL
DROP TABLE ##YourTable; -- just a precaution if it's already there
SELECT <field list>
into #YourTable -- this creates a the table with the structure of the "select" dataset
from YourSource_table
join Another_table on <join conditions>
where <your selection conditions>;
In a separate query read data from your temporary table
SELECT <field list> from #YourTable;
Make your report.
When all done, drop temporary table
IF OBJECT_ID('tempdb..#YourTable') IS NOT NULL
DROP TABLE ##YourTable;
Temporary tables accessible inside a single session; that means you must ensure you created it and read from the same connection component and keep it open in between. Other users won't see them (MS SQL server adds a unique suffix to its name)

Related

Get the table name as dynamically in ssis

I have a table in that table i'm inserting all my TableNames of that database.
Now I need to pass this table name to OLEDB source DYNAMICALLY from my main table one by one
Is this possible to to pass the table name as dynamically in OLEDB source.
I suspect you are then going to run some SQL against the stored table name?
You'll need to approach this differently and run what you are trying within a SQL task.
If not, give us some more information about exactly what you are trying to achieve.

How to assign foreign key in a master detail relationship using generator in Delphi XE2?

As an example:
I have two tables in firebird:
TB_CUSTOMER
IDCUSTOMER (autoincrement generator)
CUSTOMERNAME
TB_PHONE
IDPHONE
IDCUSTOMER (foreing key from TB_CUSTOMER)
PHONE
I have a registration form developed in Delphi. The table data TB_PHONE are handled using a dbgrid. I can not assign the value of the field IDCUSTOMER in TB_PHONE, because it was not generated by the Firebird generator. How can I make the relationship between the tables? I want to implement it without first saving the table data TB_CUSTOMER. I'm using datamodules with IBDAC.
Any sugest?
Before detail table can be inserted into, you should have PK-index over master-table updated and having proper master-ID in it. That means that some piece of code should insert master-record before inserting detail-record. Where this piece of code would be - is only limited by your fantasy.
Few arrangements include
insert the master-row in your application. Read the id of the row. Insert detail-row using this id.
read ID from then Generator, then insert both rows (master 1st) using the obtained ID
create a stored procedure, inserting both rows and returning ID (implementing #1 or #2 server-side)
use EXECUTE BLOCK - basically ad hoc anonymous SQL procedure. But that only is available in FB 2.x and except for not using namespace it is inferior to #3.
add BEFORE INSERT trigger onto detail table, searching for ID in master and adding one if not found. This would slow down all insert operations (even when master-ID already exists - that should be checked), would not be able to fill all other master columns but ID and is potentially dangerous due to hiding application logic problems. But still that can be implemented (though ugly and dirty method)
create master-join-detail VIEW and add INSERT trigger for it, propagating the new view-row into both master-table and details-table.
et cetera
I want to implement it without first saving the table data TB_CUSTOMER
There's your problem. You need the primary key from the master table before you can save the detail. That's just the way it works. But if what you want is to make sure that the values get saved together, you can do that as a transaction. In Firebird, you can do it like this:
Begin a transaction. Exactly how you do that depends on which DB library you're using to access your Firebird database.
Run an INSERT INTO ... RETURNING statement to insert the row into your master table and retrieve the generated value as a single operation.
Use the generated PK value to fill in the FK value on your detail table.
Insert the detail row.
Commit the transaction.

ASP.NET With Firebird database problems

Did you ever try to create a ASP.NET MVC Project with Firebird database...I try it, and is difficult..
My problem:
I have working Firebird provider for Visual Studio 2010.
I have correct database with all needed for increasing the id of the tables.
I have created ASP.NET MVC 3 project, with included database, like EDMX file, with entities.
When i try to insert a record into a table, there occurs a problem that says:
FirebirdSql.Data.Common.IscException: violation of PRIMARY or UNIQUE KEY constraint "PK_USERS" on table "USERS"
That means the id of the record that is created is not increased.
I have stored procedures that must generate new id.
My question is:
How to insert record in Firebird data table from ASP.NET?
In Firebird you need to use triggers in combination with sequences (generators) if you want to have auto-increment like behavior. Otherwise you need to make sure that you assign a unique id yourself.
To create the sequence:
CREATE SEQUENCE mytable_id_sq;
To create a trigger for assigning a unique i (on a table called mytable)
set term !! ;
CREATE TRIGGER T1_BI FOR mytable
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
if (NEW.ID is NULL) then NEW.ID = NEXT VALUE FOR mytable_id_sq;
END!!
set term ; !!
This trigger will only assign a generated value if no ID is assigned in the INSERT statement.
See also:
section SEQUENCE (GENERATOR) in the Firebird 2.5 Language Reference and How to create an autoincrement column? (this link talks about generators, the old name of sequences in Firebird).
Your EDMX isn't probably generated properly. Either you have to set the StoreGeneratedPattern manually or use http://blog.cincura.net/230841-generated-primary-key-in-entity-framework-model-from-firebird/ .

Auditing Changes under MVC & Entity Framework (using sprocs)

I have the challenge of needing to audit data changes made by users of an MVC application.
Auditing creation and deletion of records is easy.
Updates is proving to be the problem.
I'm looking for a way to automate this, but the problem I have is that the application is using stored procedures to bring back EF "complex types".
These are then used to build a view model, and after postback, the controller receives a new view model built from the form values passed back from the view. Therefore the original values are no longer available.
Does anyone have any suggestions for a secure way to keep the original values so they can be compared with the updated values, so that changes can be stored?
(I appreciate I could go back to the database for these, but is not efficient, and I would have to retain all the parameters to remake the same call, and find a way to automate that part of the process).
Have you tried an Audit Trigger using the INSERTED and DELETED tables.
http://weblogs.asp.net/jgalloway/archive/2008/01/27/adding-simple-trigger-based-auditing-to-your-sql-server-database.aspx
OR
In your stored procedures for insert,delete,update you can make use FOR XML AUTO. To get the XML for the record and add it to an audit table.
http://www.a2zdotnet.com/View.aspx?Id=71
UPDATE A T-SQL example
BEGIN
-- these tables would be in your database
DECLARE #table TABLE(ID INT IDENTITY(1,1) PRIMARY KEY, STR VARCHAR(10), DT DATETIME)
DECLARE #audit_table TABLE(AuditXML XML, Type VARCHAR(10), Time DATETIME)
-- this is defined at the top of your stored procedure
DECLARE #temp_table TABLE(PK INT)
-- your stored procedure will add an OUTPUT to the temp table
INSERT INTO #table
OUTPUT inserted.ID INTO #temp_table
VALUES ('test1', GetDate()),
('test2', GetDate() + 2)
-- at the end of your stored procedure update your audit table
INSERT INTO #audit_table
VALUES(
(
SELECT *
FROM #table
WHERE ID IN (SELECT PK FROM #temp_table)
FOR XML AUTO
),
'INSERTION',
GETDATE()
)
-- your audit table will have the record data
SELECT * FROM #audit_table
END
In the example above you could make temp_table a clone of table (have all of the columns from table) and in your OUTPUT clause use INSERTED.* INTO #temp_table, this would avoid have to reselect the records before getting the FOR XML AUTO. Another note, for stored procedures that do DELETE you would use DELETED.* instead of INSERTED.* in your OUTPUT.
If using SQL Server I recommend that you look into Change Data Capture (CDC).
It's an out of the box solution for auditing changes to the underlying tables of your application and it's relatively straightforward to set up, so there is no need for a custom solution that you then have to maintain.
If you have any supporting applications for your site, they'll also be covered and it also has the benefit of auditing any changes made directly against the database, such as from a DBA running a script.
Since your asp.net application may be running under one particular account, you'll probably need to add additional tracking information to capture the user who made the change. Fortunately this is also relatively straightforward. The following Stack Overflow question covers an approach to this using the ObjectStateManager
I was lookging for this myself, found this, check out Tracker for EF

Stored procedure temporary table problem?

I am using stored procedure to extract data from two different databases to a ASP.NET application. My stored procedure work as follows
- Check if global temporary table exist or not say ##temp_table
- if exist then drop it and if not create new temporary table say ##temp_table
- Extract data from two different databases and fill it to Temporary table
- Select data from temporary table
- Drop temporary table
Now problem is that when number of users accessing the same page with same stored procedure as above then to some users it get error that temporary table already exist.
Now please some one help me to solve such problem or suggest me some alternate because I don't want to write query in side ASP code. Some one suggest me to use views. Waiting for your suggestions.
"##" tables are accessible by all connections to the SQL instance, while "#" tables are accessible only by the connection that created them. The functionality you are describing sounds like you should be using "#" tables, not "##" tables.
You must not create table, you must declare variable for temporary table storage...with the column you expect to fill out...declare table variable like this:
declare #tmpTable table(myID int,myName varchar(50));
fill it like
insert into #tmpTable
Select * from table1
use it like
select * from #tmpTable

Resources