inserting multiple data into different tables using linq to entities? - c#

I'm using AdventureWorks sample database in a project. I can display the Customer's (being various stores) information using vStorewithDemographics. It's a view retrieving different pieces of data from different tables in database.
I want my program to insert a new customer into the database using linq to entities and I'm not sure how to go about this. Inserting into the view just gives me errors, which I thought would happen because it's not a table.
Any way to go about this?

yes it is possible follow following steps
--> Create a instead of trigger and using it you can perform it
Eg, I have two table customer and customerContacts latter contain the phone number of customer and a view name customer details will bring upon all the details of customer as below
create view [dbo].[CustomerDetails] as
select c.*,cc.PhoneNumber from customer c inner join customerContact cc on c.CustomerId = cc.CustomerId
For inserting in have create a instead of trigger
Create TRIGGER trgInsteadOfUpdate ON dbo.CustomerDetails
INSTEAD OF INSERT
AS
Declare #Id int
-- Insert into Customer
INSERT INTO customer SELECT CustomerName,CustomerAddress,State,Country FROM inserted
Set #Id = SCOPE_IDENTITY()
-- Insert into CustomerContact
INSERT INTO customerContact SELECT PhoneNumber,#Id FROm inserted
GO
When for inserting in the linq i can user any of the following two ways
//Insert into view
var newCusContact = new CustomerDetail{ Country="India", CustomerAddress="bbb", CustomerName="Tested", PhoneNumber="7879654", State="Delhi" };
db.CustomerDetails.InsertOnSubmit(newCusContact);
db.SubmitChanges();
OR
string insertStatement = "insert into CustomerDetails(CustomerName,CustomerAddress,State,Country,PhoneNumber) values('DummyValue','DummyValue','Delhi','India','123459')";
db.ExecuteQuery(insertStatement);
db.SubmitChanges();
Hope this helps you

Related

c# and sqlserver how to get data from second table if exists

After some advice if there is a simpler and more efficient way of what I'm about to do....
I have a table with product data in sqlserver then a frontend in asp.net c#, this has export to excel, txt file options and publish to API's.
now I need to build in that we hold certain fields like product description in a different format for certain customers,
so product table is like
PT_PRODUCT|PT_DESC |PT_SIZE
ABC123 |Super Cool Ice-Cream |small
but then for 'Customer 1' the product description needs to be 'Ice Cool Lollypop'
I was going to create a class for 'Product' in my application and fill that with the values from the main table,
then query a second table that would look like this,
CUST |PRODUCT | FIELD_ID | FIELD_VAL
CU1 |ABC123 |PT_DESC |Ice Cool Lollypop
and would run something like
select * from table2 where cust='CA1' and product='ABC123'
for(int i=0;i< ds.tables[0].rows.count;i++)
{
switch(ds.Tables[0].Rows[i]["FIELD_ID"])
{
case "PT_DESC":
ClassProd.DESC = ds.Tables[0].Rows[i]["FIELD_VAL");
//and so on updating the class
}
}
the use the updated class to update the customers site via the API or exporting to excel ect,
now for the slight curve-ball, there may be around 20+ fields that need to be overridden by the customers data, also going down this route I will be dictating the fields that can be overridden, so was wondering if there was a way of doing this in the original sql select.
You could create a stored procedure and forget about having to do any of the C# to get the customer's custom products.
This left joins the CustomerProducts table on the Product Id and the Customer Id. If it is NULL, it didn't find a customer product description so it will use the default one from the Products table. If it is NOT NULL, then it found a customer product description in CustomerProducts and uses that instead.
I don't know your schema exactly, but this is the gist:
CREATE PROCEDURE GetCustomerProducts
(
#CustomerId VARCHAR(255),
#ProductId VARCHAR(255)
)
AS
BEGIN
SELECT PRODUCT
,FIELD_ID
,CASE
WHEN cp.FIELD_VAL IS NOT NULL
THEN cp.FIELD_VAL
ELSE p.FIELD_VAL
END AS FIELD_VAL
FROM Products p
LEFT JOIN CustProducts cp ON cp.PT_PRODUCT = p.PT_PRODUCT
AND cp.CUST = #CustomerID
WHERE p.PT_PRODUCT = #ProductId
END
Then:
EXEC GetCustomerProducts #CustomerId = 'CU1', #ProductId = 'ABC123'

Multi User record update Windows application using SQL Server & C#

I am developing a windows application, where multiple users can uses the same database.
My problem is when insert a new record to database table, I need to display the new customerID in the customer registration form. For that I get the last customer id and increment by one and display the customer ID of the new customer. In a multi-user environment, if two people are trying to add a new customer at a same time, then there will be problem displaying the new customer id. And when two users accessing and updating the same record at a same time.
What to do?
You could output the inserted values into a table variable and then return that value
e.g.
DECLARE #output TABLE
(Col1 VARCHAR(10));
INSERT targetTable
(Col1)
OUTPUT inserted.Col1
INTO #output
VALUES ('ACC1001')
SELECT Col1 FROM #output;
Don't get the Last Customer Id and auto increment it by one, it's not safe for the reason you mentioned.
After the insert statement of the new record just select the inserted id and display this to the customer registration form with this line of code:
SELECT SCOPE_IDENTITY()
Or check this select statement which does the equivalent:
SELECT #RecordId= MAX([RecordId])
FROM [dbo].[CustomerTbl]

how to write insert statements for one to many relationships tables to insert with dataTable

i have 3 tables in dataset
when i click save button,
i want to add these tables to database tables using data adapter
all these 3 tables primary keys are sql generated auto number.
relation ships Invoice, InvoiceProduct , InvoiceProductExp tables are:
InvoiceNo has many InvoiceProductNo
InvoiceProductNo has many InvoiceProductExpNo
the following code can not solve these relaionship
DECLARE #InvoiceNo INT
DECLARE #InvoiceProductNo INT
INSERT INTO Invoice ([Date])
VALUES (GETDATE())
SELECT #InvoiceNo = SCOPE_IDENTITY()
INSERT INTO InvoiceProduct([InvoiceNo])
VALUES (#InvoiceNo)
SELECT #InvoiceProductNo = SCOPE_IDENTITY()
INSERT INTO InvoiceProductExp ([InvoiceProductNo], [InvoiceNo])
VALUES (#InvoiceProductNo, #InvoiceNo)
If you are using a Dataset and DataAdapter, you shouldn't be issuing all those statements. Each data adapter needs only know how to update its records. When you update the parent, the identity value will be put into your dataset automatically and the child records will automatically be set (assuming you set up your relationships correctly.) After that, you update the child tables.
Read some of the comments in this SO thread, there are some good code snippets there.

C# database update

I'm stuck on a little problem concerning database.
Once a month I get a XML file with customer information (Name, address, city,etc.). My primary key is a customer number which is provided in the XML file.
I have no trouble inserting the information in the database;
var cmd = new SqlCommand("insert into [customer_info]
(customer_nr, firstname, lastname, address_1, address_2, address_3.......)");
//some code
cmd.ExecuteNonQuery();
Now, I would like to update my table or just fill it with new information. How can I achieve this?
I've tried using TableAdapter but it does not work.
And I'm only permitted to add one XML because I can only have one customer_nr as primary key.
So basically how do I update or fill my table with new information?
Thanks.
One way would be to bulk insert the data into a new staging table in the database (you could use SqlBulkCopy for this for optimal insert speed). Once it's in there, you could then index the customer_nr field and then run 2 statements:
-- UPDATE existing customers
UPDATE ci
SET ci.firstname = s.firstname,
ci.lastname = s.lastname,
... etc
FROM StagingTable s
INNER JOIN Customer_Info ci ON s.customer_nr = ci.customer_nr
-- INSERT new customers
INSERT Customer_Info (customer_nr, firstname, lastname, ....)
SELECT s.customer_nr, s.firstname, s.lastname, ....
FROM StagingTable s
LEFT JOIN Customer_Info ci ON s.customer_nr = ci.customer_nr
WHERE ci.customer_nr IS NULL
Finally, drop your staging table.
Alternatively, instead of the 2 statements, you could just use the MERGE statement if you are using SQL Server 2008 or later, which allows you to do INSERTs and UPDATEs via a single statement.
If I understand your question correctly - if the customer already exists you want to update their information, and if they don't already exist you want to insert a new row.
I have a lot of problems with hard-coded SQL commands in your code, so I would firstly be very tempted to refactor what you have done. However, to achieve what you want, you will need to execute a SELECT on the primary key, if it returns any results you should execute an UPDATE else you should execute an INSERT.
It would be best to do this in something like a Stored Procedure - you can pass the information to the stored procedure at then it can make a decision on whether to UPDATE or INSERT - this would also reduce the overhead of making several calls for your code to the database (A stored procedure would be much quicker)
AdaTheDev has indeed given the good suggestion.
But in case, you must insert/update from .NET code then you can
Create a stored procedure that will handle insert/update i.e. instead of using a direct insert query as command text, you make a call to stored proc. The SP will check if row exists or not and then update (or insert).
User TableAdapter - but this would be tedious. First you have to setup both insert & update commands. Then you have to query the database to get the existing customer numbers and then update the corresponding rows in the datatable making the Rowstate as Updated. I would rather not go this way.

Assign names to tables in an SQL Server result set

I am writing a stored procedure that executes several successive SELECT statements. When I execute this procedure via ADO.NET, my intention is to end up with a DataSet containing several DataTable objects. This behaves as expected.
I am currently relying on the order of the tables in the DataSet to match the order of the SELECT statements in the stored procedure, however there is really no significance in this order. The person who ultimately has to maintain the procedure shouldn't have to know the expected order of the results, nor should the person maintaining the application have to know the order of the statements in the procedure.
What I want to know is, is it possible to assign names to the result of each SELECT statement within the stored procedure itself, and then have these come through via ADO.NET (hopefully seamlessly) so that I can access each table by its name instead of its order?
e.g.
// populate DataSet with results from stored proc
DataSet ds = new DataSet();
dataAdapter.Fill(ds);
// now access one of the resulting DataTable via name
return ds.Tables["NamedResultFromTheProc"];
So, is there any way to achieve this? Or will I have to rely on the order of the SELECT statements and always access the desired table by its index?
I've not tried this but could you not change the structure of the stored proc so that you have a query returning the name of the table before each data query?
i.e.
select 'TableName';
select * from Table where 1 = 1;
then build the Dataset manually by creating tables and adding them in?
The tables returned by your query will be given the names "Table", "Table1", "Table2" etc.
You can add TableMappings to your DataAdapter before filling your DataSet to map them to your table names:
myAdapter.TableMappings.Add("Table", "MyTable1");
myAdapter.TableMappings.Add("Table1", "MyTable2");
myAdapter.TableMappings.Add("Table2", "MyTable3");
Unfortunately, I do not believe this is possible! I have a similar setup which gets DataSets from Stored Procedures, and after looking I gave up and resorted to indexes.
This is also not the best solution, but you could make the first column in your query be the table name:
Select 'Customer', CustomerID, CustomerName, CustomerAddress
From Customer
Where CustomerID = #CustomerID;
Select 'Orders', OrderID, OrderPrice, OrderDate
From Order O
Join Customer C on C.CustomerID = O.CustomerID
Where C.CustomerID = #CustomerID;
Select 'OrderItems', ItemID, ItemDescription, ItemPrice
From OrderItems I
Join Order O on O.OrderID = I.OrderID
Join Customer C on C.CustomerID = O.CustomerID
Where C.CustomerID = #CustomerID;
It is not possible, but its SQL "fault", not the fault of DataAdapter/Set, because result set does not carry the name of the table queried (nor is that discernibly possible if you use inner join) nor does the table adapter have a query from which to pick the name.
One method you can use is to first return a list of tables as Query#0 in the procedure, e.g.
select 'MyTable;MySecondTable;ThirdOrSo' as tables
followed by all other queries, then read index 0 table and this field, split/forloop to rename other tables in dataset. The maintainer would still need to know the mechanism but at least it gives him some freedom to reorganize..
I've been thinking about this as well and the only solution I can think of is to create temporary tables within the procedure and populate the results into there (naming the tables as you go).
I've not tried this yet because it doesn't feel like the right way to do it with having to get the results twice (query into temp table, query the temp table).
It would be really useful if you could just rename your result set in SQL in the same way you can rename "Column AS [Custom Column]"...

Categories