Set value of a column in INSTEAD OF INSERT - c#

I have two forms namely frmSupplier and frmCustomer that allows user to add and update Customer and Supplier information. Currently we have a two table in a SQL Server database for Customer and Supplier. We are migrating the two tables into one called Contact and converted the Customer and Supplier table to a view. We did this because we want that the code in our application will no longer be modified since this will take time.
I do researched and found out INSTEAD OF INSERT triggers.
This is the SQL:
CREATE TABLE [dbo].[Contact]
(
[ContactID] [int] IDENTITY(1,1) NOT NULL,
[Code] [varchar](20) NULL,
[ContactName] [varchar](52) NULL,
[Active] [bit] NULL,
[Customer] [bit] NULL,
[Supplier] [bit] NULL,
[DeliveryAddr1] [varchar](255) NULL,
[DeliveryAddr2] [varchar](75) NULL,
[DeliveryAddr3] [varchar](75) NULL,
[DeliveryAddr4] [varchar](75) NULL,
[CreateDate] [datetime] NULL,
[LastUpdated] [datetime] NULL,
[TempID] [int] NULL,
CONSTRAINT [PK_Contact]
PRIMARY KEY CLUSTERED ([ContactID] ASC)
) ON [PRIMARY]
GO
Creating view for customers:
CREATE VIEW [dbo].[Customer]
AS
SELECT
ContactID AS CustID, Code AS CustCode,
ContactName AS CustName, Active, Customer,
DeliveryAddr1, DeliveryAddr2, DeliveryAddr3, DeliveryAddr4,
CreateDate, LastUpdated
FROM
dbo.Contact
WHERE
(Customer = 1)
GO
View for suppliers:
CREATE VIEW [dbo].[Supplier]
AS
SELECT
ContactID AS SuppID, Code AS SuppCode,
ContactName AS SuppName, Active,
DeliveryAddr1, DeliveryAddr2, DeliveryAddr3, DeliveryAddr4,
CreateDate, LastUpdated
FROM
dbo.Contact
WHERE
(Supplier = 1)
I want that when a supplier is inserted, it will insert it to Contact and set Supplier=1 or if a customer is inserted, it will set Customer=1.
This is my trigger:
CREATE TRIGGER trgNewCust
ON dbo.Contact
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO Customer
SELECT
[CustCode], [CustName], [Active],
[DeliveryAddr1], [DeliveryAddr2], [DeliveryAddr3], [DeliveryAddr4]
FROM
inserted
END
Where will I set the Customer=1 or Supplier=1? Another question is how will I know that the newly inserted item in the Contact is for supplier or customer?
Values are inserting in a C# application using INSERT INTO Customer... for customer and INSERT INTO Supplier... for supplier.

You need to have your INSTEAD OF INSERT triggers on the VIEWS - not the Contact table!
CREATE TRIGGER trgNewCust
ON dbo.Customer -- trigger must be on the VIEW - not the underlying table!
INSTEAD OF INSERT
AS
BEGIN
-- *ALWAYS* explicitly define the list of columns you're inserting into!
INSERT INTO Contact(Code, ContactName, Active, Customer, Supplier,
DeliveryAddr1, DeliveryAddr2, DeliveryAddr3, DeliveryAddr4)
SELECT
CustCode, CustName, Active, 1, 0,
DeliveryAddr1, DeliveryAddr2, DeliveryAddr3, DeliveryAddr4
FROM
inserted
END
So here, in your trigger on the Customer view, you set Customer=1, Supplier=0 - you apply the same trigger logic to the Supplier view and insert the data into the Contact table, setting Customer=0, Supplier=1
Now, from your code, if you "insert" something into the Customers view, a row in the dbo.Contact table will be created, and the same happens when you "insert" into the Supplier view.

Related

One to One relation in Entity frame work Insert

I have 2 tables, Users and Employees
CREATE TABLE [dbo].[Users](
[UserID] [int] IDENTITY NOT NULL,
[Username] [nvarchar](8) NOT NULL,
[Activo] [bit] NOT NULL,
[UltimoAcesso] [datetime] NULL,
PRIMARY KEY (UserID)
)
CREATE TABLE [dbo].[Employees](
[ColaboradorID] [int] IDENTITY(1,1) NOT NULL,
[Nome] [nvarchar](100) NOT NULL,
[Email] [nvarchar](100) NULL,
[UserID] [int] NULL
PRIMARY KEY(ColaboradorID),
UNIQUE (UserID)
)
ALTER TABLE [dbo].[Employees] WITH CHECK ADD CONSTRAINT [FK_Employees_UtilizadorID] FOREIGN KEY([UserID])
REFERENCES [dbo].[Users] ([UserID])
ON UPDATE CASCADE
ON DELETE CASCADE
I'm using Entity FrameWork Database first.
I'm trying to insert a new user
public void fvAddUser_InsertItem()
{
var item = new InventarioCiclico.Users();
using (InventarioCiclicoContext db = new InventarioCiclicoContext())
{
Employee c = new Employee ();
c.Nome = (fvAddUser.FindControl("txtNome") as TextBox).Text;
c.Email = (fvAddUser.FindControl("txtEmail") as TextBox).Text;
item.Employee.Add(c);
var employee = db.Set<Employee>();
TryUpdateModel(item);
if (ModelState.IsValid)
{
if (db.Users.Any(u => u.Username == item.Username))
{
// Handle exception
}
else
{
db.Users.Add(item);
db.SaveChanges();
var userID = item.UserID;
c.UserID = userID;
employee.Add(c);
db.SaveChanges();
}
}
}
}
However it keeps giving me exception of violation of unique value? Before starting with entity framework I would insert on Users table first, get scope_identity and insert on Employee table after and I'm trying to do this using EF6 but i don't know what can i do about this.
You are adding two employees with the same UserId in the database and since UserId is a unique field in employee table you are getting the exception of violation of unique value.
In the line item.Employee.Add(c); you are add the employee to the user, therefore, when adding the user to the database, the employee will be added two. So you don't need the last three lines:
c.UserID = userID;
employee.Add(c);
db.SaveChanges();

How to use default NEWID()/NEWSEQUENTIALID() with Guid/uniqueidentifier?

I have this table:
CREATE TABLE [dbo].[SandTable](
[Id] [uniqueidentifier] NOT NULL,
[Date] [date] NULL,
CONSTRAINT [PK_SandTable] PRIMARY KEY)
ALTER TABLE [dbo].[SandTable] ADD CONSTRAINT [DF_SandTable_Id] DEFAULT (NEWID()) FOR [Id]
Question is not about using NEWID() vs NEWSEQUENTIALID().
I use linqPad to test the table.
SandTables.InsertOnSubmit(new SandTable
{
// I don't provide any value for Id
Date = DateTime.Now
});
SubmitChanges();
My initial idea was to create an Id column that is able to initialize itself to a value when no Id is provided but will use the id provided when one is provided.
But because Guid is a struct, not a class the Id is never null, Id is initialized to his default value (00000000-0000-0000-0000-000000000000). So SQL server consider that Id has always a value and then the NEWID() default instruction is never called.
Is it possible to force the call to NEWID() on specific value? Should I use a trigger to evaluate the value of Id and when it's (00000000-0000-0000-0000-000000000000) then call NEWID()? What are the solutions or workaround?
You can do it with a check constraint:
ALTER TABLE [dbo].[SandTable]
ADD CONSTRAINT [DF_SandTable_Id] DEFAULT (NEWID()) FOR [Id]
ALTER TABLE [dbo].[SandTable]
WITH CHECK ADD CONSTRAINT [CK_SandTable_Id_Empty]
CHECK (
[Id] <> CAST(0x0 AS UNIQUEIDENTIFIER)
)

Insert/Update DataTable to SQL Server ERROR:Column name or number of supplied values does not match table definition

I have tried the following solution to try to do the insert/update data table into sql server, but some problems happended. http://www.aspsnippets.com/Articles/SqlBulkCopy--Bulk-Insert-records-and-Update-existing-rows-if-record-exists-using-C-and-VBNet.aspx
I created a table: People
CREATE TABLE [dbo].[People](
[ID] [varchar](10) NOT NULL,
[Name] [varchar](50) NULL,
[Email] [varchar](50) NULL,
[Country] [varchar](50) NULL
) ON [PRIMARY]
Create a user-defined table type : PeopleType
CREATE TYPE [dbo].[PeopleType] AS TABLE(
[ID] [varchar](10) NOT NULL,
[Name][varchar](50) NULL,
[Email][varchar](50) NULL
)
I try to use this table type to create a procedure:Update_People
CREATE PROCEDURE [dbo].[Update_People]
#tblpeople PeopleType READONLY
AS
BEGIN
SET NOCOUNT ON;
MERGE INTO People p1
USING #tblpeople p2
ON p1.ID=p2.ID
WHEN MATCHED THEN
UPDATE SET p1.Name = p2.Name
,p1.Email = p2.Email
WHEN NOT MATCHED THEN
INSERT VALUES(p2.ID, p2.Name, p2.Email);
END
but when I try to use the user-defined table type to create the procedure, An SQL server Error happened.
"Column name or number of supplied values does not match table definition."
Did I do anything wrong or miss something?
Change your Insert statement to this if you don't want to add Countries:
INSERT INTO People(Id, Email, Name) VALUES(p2.ID, p2.Name, p2.Email);
The reason you receive the error is because you don't specify which columns to use the Insert statement expects 4 as 4 are defined in the table. But ou only provide 3.
The other option is to add the Country Property to your user defined type and add the country with the procedure:
CREATE TYPE [dbo].[PeopleType] AS TABLE(
[ID] [varchar](10) NOT NULL,
[Name][varchar](50) NULL,
[Email][varchar](50) NULL,
[Country][varchar](50) NULL
)
INSERT VALUES(p2.ID, p2.Name, p2.Email, p2.Country);
EDIT: I am not sure about the syntax, since I haven't used this in a while, but it could be that you only need to provide the column names like this:
INSERT (Id, Email, Name) VALUES(p2.ID, p2.Name, p2.Email);

C# & SQL Server stored procedure - updating entity with a many-to-many relationship

At one point, there was a Node entity that had a field Alias. However, things have changed, and now we have modified that data model so that a Node can have multiple Aliases, and therefore, a Node now support an array of Aliases (which in turn creates an Aliases table, and an AliasesNodes table that maps the many-to-many relationship).
My question is, how do I update my stored procedure so that it supports this, and how do I modify the c# code that calls this stored procedure?
The requirements from the procedure is to only insert a Node if it doesn't exists, for each Alias, only insert if it doesn't exist, and finally, create the relationships between the Node and its Aliases.
OLD working stored procedure when Alias was a field (before an Alias table existed):
CREATE TYPE [dbo].[NodeTableType] AS TABLE
(
[Id] [int] NOT NULL,
[NodeTypeId] [smallint] NOT NULL,
[Location] [nvarchar](50) NULL,
[DisplayName] [nvarchar](100) NULL,
[AccessLevel] [smallint] NOT NULL,
[IsEnabled] [bit] NOT NULL,
[CreatedOn] [datetime2](7) NULL,
[CreatedBy] [nvarchar](150) NULL,
[ModifiedOn] [datetime2](7) NULL,
[ModifiedBy] [nvarchar](150) NULL,
[NativeId] [bigint] NOT NULL,
[SourceId] [int] NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[Alias] [nvarchar](100) NULL
);
CREATE PROCEDURE [dbo].[InsertNonExistingNode]
(#TableVariable dbo.NodeTableType READONLY)
AS
BEGIN
INSERT INTO NWatchNodes WITH (ROWLOCK) (Id, NodeTypeId, Location, DisplayName,
AccessLevel, IsEnabled, CreatedOn, CreatedBy,
ModifiedOn, ModifiedBy, NativeId, SourceId, Name, Alias)
SELECT
t.Id, t.NodeTypeId, t.Location, t.DisplayName,
t.AccessLevel, t.IsEnabled, t.CreatedOn, t.CreatedBy,
t.ModifiedOn, t.ModifiedBy, t.NativeId, t.SourceId, t.Name, t.Alias
FROM
#TableVariable t
LEFT JOIN
NWatchNodes PR WITH (NOLOCK) ON PR.Id = t.Id
WHERE
PR.ID IS NULL
END;

Selecting a value from one table to insert the id of the row to another one in asp.net

I'm trying the most simple insert implementation in my project for learning and to show it to my future employers. I know i should put it in another layer and call it etc but i honestly don't have enough time and i need to learn how to do it the easy way anyways.
I already have the "#username" stored in SESSION["USER"], now i need to insert into the table ORDERS the amount and the product ID, the thing is the Product name is in the PRODUCTS table.
I have the product names in a drop down list already so the USER selects the value, types the amount and then it clicks on BUY and it stores the ORDER it in the database.
What is the correct way to query this SQL command?
I was thinking the SqlCommand would do the trick but i'm still not quite sure of how to put it.
Sample from the database:
CREATE TABLE ORDERS
(
_OrderID int not null identity (1,1) primary key,
_Date datetime null,
_Quantity bigint null,
_ProdID int foreign key references PRODUCTS (_ProductID),
_UserID int foreign key references USERS (_UserID)
)
GO
CREATE TABLE PRODUCTS
(
_ProductID int not null identity(1,1) primary key,
_ProdName nchar (200) null,
_StockUnits int,
_SuppID int foreign key references SUPPLIERS (_SuppID)
)
GO
CREATE TABLE USERS
(
_UserID int not null identity(1,1) primary key,
_UserEmail varchar (35) null,
_UserName varchar (30) not null,
_UserPass varchar (30) not null,
_Name varchar (100),
_Phone varchar (20) null,
_Address varchar (150) null,
_Authority int not null,
_Special bit null
)
GO
protected void btnBuy_Click(object sender, EventArgs e)
{
//obviously incomplete.
string usrQuery = Session["NOMUSU"].ToString();
SqlConnection oConnection = new SqlConnection("Server=.\\SQLExpress;AttachDbFilename=L:\\Apps\\VS Projects\\Carnisoftix\\CarniDb.mdf;Database=CarniDb;Trusted_Connection=Yes;");
SqlCommand oCom = new SqlCommand("INSERT INTO ORDERS _Date, _Quantity VALUES " + " (" + DateTime.Now.ToString("yyyy-mm-dd HH:mm:ss") + ", "+ txtAmount.Text
}
PD: Should i make a stored procedure for this simple task?
The key to your problem is in this statement of yours:
I have the product names in a drop down list already
When you build that dropdown list you can add the Id of the products and use it as the value in the dropdown such that you will have something like this:
<select>
<option value="1">Apple</option>
<option value="2">Banana</option>
<option value="3">Orange</option>
</select>
Then you pass/get that value in your code-behind, similar to how you get the value of the amount from txtAmount. In that manner you don't have to query the products table by name just to get the _ProductID so you can insert it into the ORDERS table.

Categories

Resources