SQL Server 2005: Basic Insert / Record Logic Help Needed - asp.net

I am designing a social networking site that has a "wall" feature like the others out there today. The database has an alerts table that stores some user action worthy of sharing with his friends. For example, when a user updates his status, all of his friends are notified. The below table shows two status updates from two unique users. The first (AlertId 689 and 690) is submitted by AccountId 53. Since he has one frinend - AccountId 57 - that row is added to the table so when this user logs on, he will see Account 53's update on his wall. In the same manner, the other user's status update has four rows because he has three friends.
[AlertId] [AccountId] [CreateDate] [Timestamp] [AlertTypeId] [IsHidden] [Body]
689 57 2010-08-10 0x0000000000018725 10 0 HTML
690 53 2010-08-10 0x0000000000018726 10 0 HTML
691 53 2010-08-10 0x000000000001872B 10 0 HTML
692 52 2010-08-10 0x000000000001872C 10 0 HTML
693 51 2010-08-10 0x000000000001872D 10 0 HTML
694 57 2010-08-10 0x000000000001872E 10 0 HTML
Now, a user can comment on any given item, in this case a statusupdate. When AddComment is submitted, we are using ObjectRecordId (which is the primary key of the alert being commented on) in order to identify which statusupdate is being commented on (fyi - the objectId tells us its a statusupdate):
public void AddComment(string comment)
{
if (_webContext != null)
{
var c = new Comment
{
Body = comment,
CommentByAccountId = _webContext.CurrentUser.AccountId,
CommentByUserName = _webContext.CurrentUser.UserName,
CreateDate = DateTime.Now,
SystemObjectId = _view.ObjectId,
SystemObjectRecordId = _view.ObjectRecordId
};
_commentRepository.SaveComment(c);
}
_view.ClearComments();
LoadComments();
}
Now, the problem is that when a user wants to comment on a friend's status update, he will be using the AlertId (or ObjectRecordId in the Comments table) corresponding to his account in the alerts table. The result is that comments are only viewable by the commenter and none of his friends:
[CommentId] [Body] [CommentById] [CommentByName] [ObjectId] [ObjectRecordId] [Delete]
97 hello world. 57 GrumpyCat 7 690 0
Of course the solution to this is to do something similar to what I did in the alerts table - when somebody makes a comment, make a corresponding row for every friend in the comments table. But how do I access the AlertIds of all of my friend's status updates in the Alerts table and map them to the ObjectRecordId column in the comments table? Since I can only access the status updates corresponding to my account (and their corresponding alertids), I don't know what the alertids are for the same statusupdate in my friend's accounts.
The only solution that I can think of right now is stuffing the hidden field with all of my friend's corresponding alertIds so when I comment on an item, i already know what they are. But this feels sloppy and I'd like to know if there are any better ideas out there?
For what it is worth, here is the CREATE TABLE of dbo.Alerts:
CREATE TABLE [dbo].[Alerts](
[AlertId] [bigint] IDENTITY(1,1) NOT NULL,
[AccountId] [int] NOT NULL,
[CreateDate] [datetime] NOT NULL CONSTRAINT [DF_Alerts_CreateDate] DEFAULT (getdate()),
[Timestamp] [timestamp] NOT NULL,
[AlertTypeId] [int] NOT NULL,
[IsHidden] [bit] NOT NULL CONSTRAINT [DF_Alerts_IsHidden] DEFAULT ((0)),
[Message] [varchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
CONSTRAINT [PK_Alerts] PRIMARY KEY CLUSTERED
(
[AlertId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
And, here is dbo.Comments:
CREATE TABLE [dbo].[Comments](
[CommentId] [bigint] IDENTITY(1,1) NOT NULL,
[Timestamp] [timestamp] NOT NULL,
[Body] [varchar](2000) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[CreateDate] [smalldatetime] NOT NULL,
[CommentByAccountId] [int] NOT NULL,
[CommentByUserName] [varchar](250) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[SystemObjectId] [int] NOT NULL,
[SystemObjectRecordId] [bigint] NOT NULL,
[FlaggedForDelete] [bit] NOT NULL CONSTRAINT [DF_Comments_FlaggedForDelete] DEFAULT ((0)),
CONSTRAINT [PK_Comments] PRIMARY KEY CLUSTERED
(
[CommentId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
I am using SQL Server 2005. Thanks in advance.

Update
I have some real concerns about your design, I've layed them out using scenarios. I named one of my concerns earlier, which is that I don't see any way of tieing an alert back to a comment.
Scenario: A friend posts on his wall saying "hey, i'm giving away my old computer, let me know if you want it". Of course you weren't able to access the site for two weeks due to some good reason. Now when you finally get back on and see the alert for your friends posting you want to go check it out, BUT! there is nothing tieing this alert back to a comment. So when you click it you just go to your friends wall and not stright to the posting. You should be able to click an alert and go straight to the comment/post but I don't see any way of doing this right now.
Secondly, I don't see anyway of replying to a comment.
Scenario: I go to friend X's page and see that he's in texas this week for business, and I want to comment on that. So I write in the text box "hey, bring me back a present" and submit it. Now what happens to this comment? It goes in the comments table with a comment ID and it has my ID attached to it, but where does anything in the database say that it is a reply to a comment?
I think if you solve some of these other design issues the issue will probably fix itself, or if I'm way off or there are other tables in the picture that aren't included let me know.
Original Post
It looks like you need an extra column in the Alerts table, at least as far as I can tell. Here is the question I asked myself: How do I tell, just by looking at any record in the Alerts table, what comment it belongs to? I can't as far as I know. This means that the Alert is very general "hey this user said something, but I don't know what and if he removes his comment this little alert will still be here because it's not attached...".
So, I think you need a column in the Alerts table that links it back to the original comment/posting/whatever. Now you can use that original "CommentID" (?) to make the posting and everything works out clean and pretty.
I know I didn't directly answer your actual question... but I think your table design might need some work.

Related

How can I implement a reflexive primary/foreign key relationship in Access?

MS Office 265 ProPlus, Access 2007 - 2016
I'm a novice with this.
I have a table called pedigree. I has 3 columns...
Name (text)
ID (auto increment integer, primary key)
Parent_ID (integer)
I want to implement a constraint which will require that the "parent_ID" value of each record exists as the ID value of some other record i the same table (a reflexive primary/foreign key setup).
In Access, I went to the "Database Tool" tab, then "Relationships", then opened the table up twice and tied that ID column of one to the "Parent_ID" of the other. It didn't complain, saved out OK. When I run it, it doesn't seem to work. I can put records in the table with Parent_ID values outside of the available ID value pool.
Any clues?
Also, if there's a different/better way to do this, I'm all ears. I read about the "Database Tools" -> "Relationships" approach on the web somewhere but am open to anything that might work.
And the solution for me (the novice) was...
Set the "Enforce Referrential Integrity" of the relationship.
Thanks Gustav for the hint !

Control can't be edited; it's bound to AutoNumber field [FieldName]

I have a Microsoft Access ADP-type database, linking to a SQL Server 2012 database, which was recently upgraded from Office XP (2002) to Office 2010. The upgrade was mostly successful except for an issue with a Combo Box on a form with an updateable data source - In Access XP/2002, the user could select values from the dropdown list and the value would be updated in the table. However, when the user tries to modify the record using the 'tblL.LMID' Combo Box in Access 2010, an error briefly flashes in the status bar at the bottom of the screen (and the record is not updated):
"Control can't be edited; it's bound to AutoNumber field 'LMID'"
I understand this is normal functionality if the field in question was an Identity column in SQL Server, but that's not the case here. However, the 'tblL.LMID' field does get used as a join in the SQL query behind the scenes.
The data source on the form is as follows:
SELECT dbo.tblLM.OpID, dbo.tblL.*, dbo.tblLM.DR
FROM dbo.tblL INNER JOIN dbo.tblLM ON dbo.tblL.LMID = dbo.tblLM.LMID
WHERE (dbo.tblLM.DR = 1)
ORDER BY dbo.tblL.DS
The tables involved in the query are as follows:
CREATE TABLE [dbo].[tblL](
[LID] [int] IDENTITY(1,1) NOT NULL,
[LMID] [int] NOT NULL,
[DS] [nvarchar](10) NOT NULL)
CREATE TABLE [dbo].[tblLM](
[LMID] [int] IDENTITY(1,1) NOT NULL,
[OpID] [int] NULL,
[DR] [bit] NULL DEFAULT ((1)))
As per the table structure, tblL.LMID is a simple column (not Autonumber/Identity), and we should be able to modify it like we did in the Access XP/2002 version of the application.
I would happily accept any assistance on this issue, much appreciated! :)
The problem was with the query itself. To resolve, we had to replace the "dbo.tblL.*" select with specific column names, as well as giving the problematic column an alias:
SELECT dbo.tblLM.OpID, dbo.tblL.LMID as l_MID, dbo.tblLM.DR
FROM dbo.tblL INNER JOIN dbo.tblLM ON dbo.tblL.LMID = dbo.tblLM.LMID
WHERE (dbo.tblLM.DR = 1)
ORDER BY dbo.tblL.DS
We then updated the combo box to use the new alias ("l_MID"), and then it started working correctly.
Put the form into design view; delete the current combobox. Create a new combobox and follow the wizard.

Entity Framework Inserting Multiple Copies of Same Data

I am having a strange problem with Entity Framework and SQL Server that I cannot figure out.
I am building an online store in ASP.NET MVC 5.
I am inserting statistics about a search into a table called SearchResults - it has this structure:
[SearchID] [int] IDENTITY(1,1) NOT NULL,
[SearchTerm] [varchar](5000) NULL,
[SearchDate] [datetime] NULL,
[Results] [int] NULL
I am just doing a simple EF insert with this C# code in the Search action of a controller, which gets posted to with a search term:
var s = new SearchResult() { SearchTerm = search, SearchDate = DateTime.Now, Results = results };
db.SearchResults.Add(s);
db.SaveChanges();
Results is an int with the count of the products found by the search.
Whenever I do a search, the same search gets inserted exactly 3 times, with slightly different times for each insert. The weird part is that occasionally, it will only insert one entry (as expected). I can't figure out why it is doing this.
I've run an SQL trace, and when it inserts 3, there is only one call to the DB. This is what is in the trace:
exec sp_executesql N'INSERT [dbo].[SearchResults]([SearchTerm],[SearchDate], [Results])
VALUES (#0, #1, #2)
SELECT [SearchID]
FROM [dbo].[SearchResults]
WHERE ##ROWCOUNT > 0 AND [SearchID] = scope_identity()',N'#0 varchar(5000),#1 datetime2(7),#2 int',#0='dew',#1='2015-02-16 16:32:53.4649185',#2=2
The weird part is the datetime shown in the insert is the value for the third insert.
I am at a complete loss for why this is happening. I've tried everything I can think of, but I am still getting repeats on insert.
Maybe you're looking at the wrong piece of code.
Had you logged or debugged the calls to the controller, how many times the first snippet of code you posted get executed?

Can't create nodes after DB-Import (Duplicate Entries)

i exported a bunch of tables and prefixed them with "ch_" and imported them again. All using phpmyadmin. It all works fine… until I want to create something. It fails with this message:
user warning: Duplicate entry '4-4' for key 'PRIMARY' query: INSERT INTO ch_node (nid, vid, title, type, uid, status, created, changed, comment, promote, sticky) VALUES (4, 4, 'Nützliche Dokumente', 'page', 1, 1, 1288790996, 1288791130, 0, 0, 0) in /var/www/clients/client20/site60/docroot/includes/database.mysql.inc on line 172.
Whereas the '4-4' increments each time i try to save. That made me think the auto_increment value in the DB is somehow wrong - though it was correctly specified in my export.sql. Hence I tried to reset the auto_increment value to some ridiculous high number using ALTER TABLE some_table AUTO_INCREMENT=10000. Still same behaviour…
Anyone an idea what's going on here?
I did this procedure a few times before … but without this happening. It's driving me nuts :/
So, your import works fine, it's only when you try to insert a new record after everything has been imported that you get this error? If that's the case, then either:
Your auto_increment isn't set correctly.
You are specifying a value for your auto_increment field.
From the post above, it looks like you're specifying a value for your auto_increment field. You should update your auto_increment to the MAX+1 of your table, and then when you do you're insert, don't specify a value for that field and MySQL will use the auto_increment for you...
Lesson learned:
Drupal does not use MySQL's auto_increment value.
As I learned auto increment is not part of the SQL Ansi standard - it's just a very common thing. Drupal does not want to rely on some implementations of different RDBMS, so they have a table {sequences} that has a column for the table name and the next id-value that can be loaded with db_next_id($name). Of course by prefixing the table names, I had to add the prefix in the sequences table as well.
As much as it drove me nuts in the first place, I think it's a wise decision the drupal-developers made.

Recursive Query using HQL

I have this Table
CREATE TABLE IF NOT EXISTS `branch` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`studcount` int(11) DEFAULT NULL,
`username` varchar(64) NOT NULL,
`branch_fk` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FKADAF25A2A445F1AF` (`branch_fk`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=14 ;
ALTER TABLE `branch`
ADD CONSTRAINT `FKADAF25A24CEE7BFF` FOREIGN KEY (`login_fk`) REFERENCES `login` (`id`);
as you can see each table has a foreign key that point to other Branch Row (self Relation)
I want a Query using HQL(prefer HQL) to get a username (or id) from me and return a List<String> (for username) or List<Integer> (for id) that was a list of all of my subBranch;
let me show in Example
id studentcount username branch_fk
1 312 user01 NULL
2 111 user02 1
3 432 user03 1
4 543 user04 2
5 433 user05 3
6 312 user06 5
7 312 user06 2
8 312 user06 7
when I call GetSubBranch(3) I want return:
5, 6
and when call GetSubBranch(2) I want return:
4, 7, 8
I believe there is no portable SQL to do this.
Even more, I think several major databases' SQL cannot express this.
Therefore, this capability is not part of what you can do in HQL. Sorry :-(
I read a few ways to go. Most of them involve tradeoffs depending of the number of levels (fixed in advance ? how many ?) , the number of records (hundreds ? millions ?) etc :
Do the recursive queries yourself, leveling down each time (with a in(ids)), until some level is empty.
Do a query with a fixed number of left joins (your depth need to be known in advance ; or you might need to repeat the query to find the rest of the records if needed, see point 1).
Have the denormalized information available somewhere : it could be a denormalized table copying of the indexes. But I would prefer a cached in-memory copy, that may be filled completely in only one request, and be updated or invalidated ... depending on your other requisites, like the table size, max depth, write-frequency etc).
One may have a look at 'nested sets'. Querying becomes a matter of 'between :L and :R'. But topological/hierarchical sort is lost (in comparison to recursive/hierarchical queries). Inserting new items then is quite costly as it requires updates on several if not all rows ...

Resources