Dataset and self referencing relationships Insert Exception - c#

I am using c# datasets with a MSSQL back end. I have a table that references itself. When I add a parent row then add a child to that, without calling update in between I am getting a constraint exception. I think it is because the inserts are not being performed in the same order the entities were added. Is there any ways around this? I want the user to be able to add items and then commit to the database at the end (when they have confirmed it is all correct).
Here is my table definition and a sample application:
CREATE TABLE [dbo].[AssetServiceItems] (
[ServiceItemID] [int] IDENTITY(1, 1) NOT NULL,
[Description] [nvarchar](50) NOT NULL,
[Parent] [int] NULL,
CONSTRAINT [PK_AssetServiceItems] PRIMARY KEY CLUSTERED ([ServiceItemID] ASC) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[AssetServiceItems]
WITH CHECK ADD CONSTRAINT [AssetServiceItems_parent] FOREIGN KEY ([Parent]) REFERENCES [dbo].[AssetServiceItems]([ServiceItemID])
ALTER TABLE [dbo].[AssetServiceItems] CHECK CONSTRAINT [AssetServiceItems_parent]
and the program...
public static void Main(string[] args)
{
RelTestTableAdapters.AssetServiceItemsTableAdapter adapter = new RelTestTableAdapters.AssetServiceItemsTableAdapter();
RelTest dataSet = new RelTest();
var parent = dataSet.AssetServiceItems.NewAssetServiceItemsRow();
parent.Description = "Parent";
dataSet.AssetServiceItems.AddAssetServiceItemsRow(parent);
var child = dataSet.AssetServiceItems.NewAssetServiceItemsRow();
child.Description = "child";
child.SetParentRow(parent);
dataSet.AssetServiceItems.AddAssetServiceItemsRow(child);
adapter.Update(dataSet);
Console.ReadKey(true);
}
The INSERT statement conflicted with the FOREIGN KEY SAME TABLE
constraint "AssetServiceItems_parent". The conflict occurred in
database "RelTest", table "dbo.AssetServiceItems", column
'ServiceItemID'.

Related

EntityFramework mapping table wrong

I have 2 tables:
Categories and
Users
The CategoryId is an int and the UserId is a string (nvarchar(128)).
I have this mapping for my user:
this.HasMany(t => t.ForbiddenCategories)
.WithMany(t => t.ForbiddenUsers)
.Map(m =>
{
m.ToTable("UserForbiddenCategories");
m.MapLeftKey("CategoryId");
m.MapRightKey("UserId");
});
but when I create a database for this, it does this:
CREATE TABLE [dbo].[UserForbiddenCategories](
[UserId] [int] NOT NULL,
[CategoryId] [nvarchar](128) NOT NULL,
CONSTRAINT [PK_dbo.UserForbiddenCategories] PRIMARY KEY CLUSTERED
(
[UserId] ASC,
[CategoryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[UserForbiddenCategories] WITH CHECK ADD CONSTRAINT [FK_dbo.UserForbiddenCategories_dbo.Categories_UserId] FOREIGN KEY([UserId])
REFERENCES [dbo].[Categories] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[UserForbiddenCategories] CHECK CONSTRAINT [FK_dbo.UserForbiddenCategories_dbo.Categories_UserId]
GO
ALTER TABLE [dbo].[UserForbiddenCategories] WITH CHECK ADD CONSTRAINT [FK_dbo.UserForbiddenCategories_dbo.IdentityUsers_CategoryId] FOREIGN KEY([CategoryId])
REFERENCES [dbo].[IdentityUsers] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[UserForbiddenCategories] CHECK CONSTRAINT [FK_dbo.UserForbiddenCategories_dbo.IdentityUsers_CategoryId]
GO
which is completely the wrong way around. CategoryId should be the int with a FK to Categories and UserId should be the string with a FK to IdentityUsers.
Can anyone tell me what I am doing wrong? Or how I can tell EF to change the maps around?
Cheers,
/r3plica

Saving server date and time

I want to save the time and date within my news but in the method below I save the time of the user and if his/her time is wrong, the wrong time will be save. How can I use the server's time instead.
SqlConnection sqlconn = new SqlConnection(connStr);
SqlCommand sqlcmd = new SqlCommand("insert into SubmitManuscript(username,title,authors,type,date,upload,reviewer1,email1,reviewer2,email2,reviewer3,email3)values(#username,#title,#authors,#type,#date,#upload,#reviewer1,#email1,#reviewer2,#email2,#reviewer3,#email3)", sqlconn);
sqlcmd.Parameters.AddWithValue("#username", username);
sqlcmd.Parameters.AddWithValue("#title", Text_Title.Text);
sqlcmd.Parameters.AddWithValue("#authors", Text_Author.Text);
sqlcmd.Parameters.AddWithValue("#type", dd_Type.SelectedItem.Text);
sqlcmd.Parameters.AddWithValue("#date", DateTime.Now);
//sqlcmd.Parameters.AddWithValue("#upload", "~/Suppelment/" +
There is no need to pass datetime parameter. Just set a datetime as default value in your table in the Database. That should do the trick.
Here is a link how to set this in table generation script:
How to set the default value for a datetime column
Edit: Your table needs to have a special DateTimeStamp column that will set system-datetime automatically when you insert a record. I am putting a simple script that you may use as an example.
Note: If you already have table in place then just start from script ALTER TABLE
CREATE TABLE [dbo].[Employee]
(
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
[BirthDate] [datetime] NOT NULL,
[LastUpdateTime] [datetime] NOT NULL,
CONSTRAINT [PK_Employee]
PRIMARY KEY CLUSTERED ([EmployeeId] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Employee]
ADD CONSTRAINT [DF_Employee_LastUpdateTime]
DEFAULT (getdate()) FOR [LastUpdateTime]
GO
--- You may also use multiple record insert statement in SQL Server 2008
--- however, I will use a traditional approach here
INSERT INTO [dbo].[Employee] (Name, BirthDate)
VALUES ('Smith', '04/14/1979')
INSERT INTO [dbo].[Employee] (Name, BirthDate)
VALUES ('Jhone', '11/08/1983')
GO

Remove() does not work on a many-to-many relationship (ASP.NET, lambda expressions)

I am working with C# and ASP.net (4.0). I am trying to remove a record in my InterestsProfiles table using lambda expressions. The table has only two columns: profile id and interest id, and these are foreign keys to the Profiles table (id) and the Interests table (id).
So I managed to add to the Interests profiles table with the following code (the arguments to the function are string profileID, string name (of the interest)):
var interest =
context.a1Interests.Where(i => i.Interest.ToLower() == name.ToLower()).First();
if (interest == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
// Grab the profile
a1Profile profile = context.a1Profiles.Find(_id);
// Create a new profile that will be modified
a1Profile newProfile = profile;
if (profile == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
// Associate the interest with this profile
newProfile.a1Interests.Add(interest);
// Replace the old profile with the new one and save the changes
context.Entry(profile).CurrentValues.SetValues(newProfile);
context.SaveChanges();
I thought I could just do the opposite for removal, using .Remove(), but it does not work. The function returns the correct object and the status is 200/OK, but the entry in InterestsProfiles itself is not deleted.
newProfile.a1Interests.Remove(interest);
// Replace the old profile with the new one and save the changes
context.Entry(profile).CurrentValues.SetValues(newProfile);
context.SaveChanges();
The creation script for the table is this:
CREATE TABLE a1InterestsProfiles(
[Profile] [int] NOT NULL,
[Interest] [int] NOT NULL,
CONSTRAINT [PK_a1InterestsProfiles] PRIMARY KEY CLUSTERED
([Profile] ASC, [Interest] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]) ON [PRIMARY]
GO
-- Foreign key - Profiles
ALTER TABLE a1InterestsProfiles
ADD CONSTRAINT [FK_a1InterestsProfiles_Profiles]
FOREIGN KEY ([Profile]) REFERENCES a1Profiles([ID])
GO
ALTER TABLE a1InterestsProfiles CHECK CONSTRAINT [FK_a1InterestsProfiles_Profiles]
GO
-- Foreign key - Interests
ALTER TABLE a1InterestsProfiles
ADD CONSTRAINT [FK_a1InterestsProfiles_Interests]
FOREIGN KEY ([Interest]) REFERENCES a1Interests ([ID])
GO
ALTER TABLE a1InterestsProfiles CHECK CONSTRAINT [FK_a1InterestsProfiles_Interests]
GO
Please help. I thought this would be really straightforward.
You need to .Attach() and entity when editing it;
to add
a1Profile profile = context.a1Profiles.Find(_id);
a1Profile.a1Interests.Add(interest);
context.SaveChanges();
to remove
newProfile.a1Interests.Remove(interest);
context.a1Profiles.Attach(newProfile);
context.SaveChanges();
Also worth looking at EntityState.Modified

SQL SELECT From two tables (friendship) statement

I have the following tables created:
Table #1: tbl_Connections
USE [taaraf_db]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tbl_Connections](
[uc_Id] [int] IDENTITY(1,1) NOT NULL,
[uc_User] [nvarchar](50) NOT NULL,
[uc_Connection] [nvarchar](50) NOT NULL,
[uc_IsPending] [int] NOT NULL,
[uc_DateTime] [datetime] NOT NULL,
CONSTRAINT [PK_tbl_Connections] PRIMARY KEY CLUSTERED
(
[uc_Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[tbl_Connections] ADD CONSTRAINT [DF_tbl_Connections_uc_IsPending] DEFAULT ((1)) FOR [uc_IsPending]
GO
Table #2: tbl_LiveStream
USE [taaraf_db]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tbl_LiveStreams](
[ls_Id] [int] IDENTITY(1,1) NOT NULL,
[ls_Story] [nvarchar](max) NOT NULL,
[ls_User] [nvarchar](50) NOT NULL,
[ls_Connection] [nvarchar](50) NOT NULL,
[ls_DateTime] [datetime] NOT NULL,
CONSTRAINT [PK_tbl_LiveStreams] PRIMARY KEY CLUSTERED
(
[ls_Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Now uc_User in tbl_Connections represents the user who initiated a friend request, and uc_Connection
represents the other party.
Same concept is applied on the second table (tbl_LiveStreams)
I am trying to select all new LiveStreams for a cetrain user, LiveStream should be retrieved for a specific user only if that user is connected to the other party (uc_IsPending = 0)
I have a C# function that takes the following arguments:
public static DataTable GetAsyncLiveStream(string CurrentUser, int startAt, int howMany) { ... }
And with the above, a DataTable should return all new items in LiveStream for the given CurrentUser (ls_User) if the requirements specified above are true.
This is sort of like the Facebook news feed, what's happening with friends etc...
Oh yeah, tbl_LiveStream is populated whenever someone (ls_User) initates some sort of specific event to (ls_Connection).
I'm not sure if i'm complicating my life here but that's what I have and all help is appreciated.
I should mention that I've done this by looping through all returned records from tbl_LiveStream and done some validation using a custom class function .IsFriends() that will go and check for friendship status in the database and programatically populates a DataTable... Which is sort of stupid, I admit. But I'm not sure how to do this.
One last thing,
I'm using the following query to return limited results:
SELECT * FROM (
SELECT row_number() OVER (ORDER BY ) AS rownum, ls_Id
FROM )
AS A
WHERE A.rownum BETWEEN (#start) AND (#start + #rowsperpage)
Please help and thank you for your time.
EDIT
I'd like to note that this is how I am fetching who's friends with who from the tbl_Connections Table.
const string sql = "SELECT REPLACE((uc_Connection + uc_User), #CurrentUser, '') AS Connection " +
"FROM tbl_Connections Connection " +
"WHERE (#CurrentUser = uc_Connection) OR (#CurrentUser = uc_User)";
SELECT * FROM (
SELECT row_number() OVER (ORDER BY ) AS rownum, ls_Id
FROM )
AS A
WHERE A.rownum BETWEEN (#start) AND (#start + #rowsperpage)
This syntax is wrong. You can't do it like that. Use a Union, or use LINQ to SQL.
From a critique perspective, don't get DataTables, get Entities. You seem to be over complicating quite a bit here, with technologies you may not be familiar with. I'd advise taking all currently existing data and dumping it to a CSV file, then starting the application from scratch with something like Sharp Architecture, which can abstract away some of these details for you.

Linq To Sql duplicate a row in update case

I have a single entity that always duplicate a row when it needs to update:
protected static Task RegisterToDisc(Task task)
{
try
{
using (DataContext context = new DataContext())
{
//this will print an actual existing id from the db
_log.Debug(task.ID);
context.Tasks.InsertOnSubmit(task);
context.SubmitChanges();
}
}
catch(Exception e)
{
//...
}
return task;
}
When I print the id before the save, it is actually prints out an id that is really exists in the db.
this is the table:
CREATE TABLE [dbo].[TaskSet](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Message] [nvarchar](max) NOT NULL,
[Result] [nvarchar](max) NOT NULL,
[Status] [int] NOT NULL,
[Priority] [int] NOT NULL,
[Name] [nvarchar](max) NOT NULL,
[DateTimeAsked] [datetime] NOT NULL,
[DateTimePerfomed] [datetime] NOT NULL,
[SessionID] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_TaskSet] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Edit
The task is comming from the database already, task.ID contains a number that is exists in the database, how come Linq inserts an entity with PK that is not null and in the db already.
in java hibernate you neet to context.insertOrUpdate(task); and it will decide what to do by the primary key.
InsertOnSubmit always marks the object for insertion. if you want to update the object u need to read it from database like
var objToUpdate = context.Tasks.SingleOrDefault(x=>x.Id == Id);
objToUpdate.Property1 = "updated value";
objToUpdate.Property2 = "updated value";
//do it for all properties that need updating
context.SubmitChanges();//since the object is tracked by context it will automatically generate sql to reflect update in db

Categories