Retrieve and iterate data using JOIN in C# MVC4 - c#

I am not getting how to iterate data that is retrieved using join.
Table project images
[img_id] INT IDENTITY (1, 1) NOT NULL,
[proj_id] INT NOT NULL,
[path] NVARCHAR (50) NOT NULL,
PRIMARY KEY CLUSTERED ([img_id] ASC),
CONSTRAINT [FK_projimg_projects] FOREIGN KEY ([proj_id]) REFERENCES [dbo].[Projects] ([proj_id])
Table Projects
[proj_id] INT IDENTITY (1, 1) NOT NULL,
[proj_name] NVARCHAR (50) NOT NULL,
[step1] NVARCHAR (MAX) NOT NULL,
[step2] NVARCHAR (MAX) NOT NULL,
[step3] NVARCHAR (MAX) NOT NULL,
[step4] NVARCHAR (MAX) NOT NULL,
[user_id] INT NOT NULL,
[materials] NVARCHAR (MAX) NOT NULL,
[tag] NVARCHAR (50) NOT NULL,
PRIMARY KEY CLUSTERED ([proj_id] ASC),
CONSTRAINT [FK_Projects_user] FOREIGN KEY ([user_id]) REFERENCES [dbo].[Users] ([user_id])
i retrieved the data using following query
var tutorial = from proj in de.Projects
join image in de.projimgs
on proj.proj_id equals image.proj_id
select new {
proj.proj_name,
proj.materials,
proj.step1,
proj.step2,
proj.step3,
proj.step4,
image.path,
};
and now i want to iterate the data, each project containing multiple images, how do i show those images in single iteration of foreach loop. Can anyone help clearly.
Thankx in advance.

Well you can iterate then in two foreach loop like
foreach(project p in tutorial)
{
foreach(image in p.Images)
{
//Do your processing
}
}

First, if you have your foreign keys set up as mapped properties, Rahul's answer is the easiest. If you actually need to do a join, your query isn't quite right.
Keep in mind what your SQL statement is doing. When you do an INNER JOIN, you're asking for one result per combination of values. Your query is equivalent (roughly) to:
SELECT proj.proj_name, proj.proj_name, proj.materials, proj.step1, proj.step2, proj.step3, proj.step4, image.path
FROM Project proj
INNER JOIN Project_Images image ON image.ProjectId = proj.Id
Given your select statement, you will get back multiple copies of the project - one for each image. You just loop over those results.
It sounds like what you wrote is incorrect and what you actually want is a group by:
var tutorial = from proj in de.Projects
join image in de.projimgs on proj.proj_id equals image.proj_id
group image by proj into groupedImages
select new { Project = groupedImages.Key, Images = groupedImages };
Then you loop over it:
foreach (var project in tutorial)
{
// Do what you want with project here
foreach (var image in project.Images)
{
// Do what you want with image here
}
}

Related

Specify a custom default value generating function in SQL Server

I'm creating the following table:
CREATE TABLE [dbo].[Symptoms]
(
[Id] INT NOT NULL,
[description] NVARCHAR (128) NOT NULL,
[imgPath] NVARCHAR (128) NOT NULL,
[diseaseId] INT NOT NULL,
[weight] FLOAT NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC, [diseaseId] ASC)
);
What I want to do is create a default value for the [imgPath] column. I know about DEFAULT newid() and other methods, but I want a custom generated method.
Specifically, I want the [imgPath] to be $"/resources/Images/{Id}_symptom.jpg" where Id is the ID of that specific row.
Where can I specify this function?
Thanks!
Update
Column defaults in SQL Server can't be made up using other columns data.
What you can do is add another column for you to specify the image path, and use it as a part of the computed column's declaration:
CREATE TABLE [dbo].[Symptoms] (
[Id] INT NOT NULL,
[description] NVARCHAR (128) NOT NULL,
[UserDefinedImgPath] NVARCHAR (128) NULL,
[imgPath] AS COALESCE(UserDefinedimgPath, '/resources/Images/' + CAST(Id AS NVARCHAR(13)) +'_symptom.jpg') PERSISTED,
[diseaseId] INT NOT NULL,
[weight] FLOAT NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC, [diseaseId] ASC)
);
Now, when you want to specify the image page on insert or update, use the UserDefinedImgPath column. When you want the default value, simply leave it null.
When selecting the image path, always use the computed column.
First answer
Use a computed column for imgPath:
CREATE TABLE [dbo].[Symptoms] (
[Id] INT NOT NULL,
[description] NVARCHAR (128) NOT NULL,
[imgPath] AS '/resources/Images/' + CAST(Id AS NVARCHAR(13)) +'_symptom.jpg' PERSISTED,
[diseaseId] INT NOT NULL,
[weight] FLOAT NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC, [diseaseId] ASC)
);
Note that you can't update a computed column, nor can you insert a specific value to it.
To add default value please create default constraint, in SQL Server the example is below:
ALTER TABLE Symptoms
ADD CONSTRAINT Symptoms_imgPath
DEFAULT (('/resources/Images/{Id}_symptom.jpg')) FOR imgPath
Other way is to insert default value at the time of insert, like this:
INSERT INTO Symptoms
SELECT '/resources/Images/{Id}_symptom.jpg'
FROM symptoms
WHERE id = NEWID()

Trying to Insert records into table Error on FK T-SQL

I'm trying to insert new text book records into a a database. I have a Course table with columns ID (PK), CourseID, CourseTitle.
textBook table (all columns, ID (PK)) is a many to many relationship so multiple courses can have the same book and courses can also have multiple different books.
When I try to insert a new text book into my database using C# I get an error on my foreign key. The Course table is parent, Textbook table is child. The ID column in both tables is set to identity and auto increments. ID is my foreign key in my textBook table referencing the Course table.
here is my intermediate table.
CREATE TABLE [dbo].[BookCourse]
(
[cID] INT NOT NULL Unique,
[BookID] INT NOT NULL Unique,
[BookCourseID] INT NOT NULL,
CONSTRAINT [PK_BookCourse] PRIMARY KEY ([BookCourseID])
)
here is my textBook table
CREATE TABLE [dbo].[textBooks] (
[thirteenISBN] VARCHAR (255) NOT NULL,
[CourseID] VARCHAR (50) NOT NULL,
[BookTitle] VARCHAR (255) NULL,
[Ancillary] VARCHAR (255) NULL,
[BookActive] VARCHAR (20) NULL,
[ActiveDate] VARCHAR (50) NULL,
[InactiveDate] VARCHAR (50) NULL,
[Author] VARCHAR (255) NULL,
[Imprint] VARCHAR (100) NULL,
[Publisher] VARCHAR (100) NULL,
[EditionAndDate] VARCHAR (120) NULL,
[tenISBN] VARCHAR (255) NULL,
[VendorISBN] INT NULL,
[ebookAvailable] VARCHAR (50) NULL,
[eISBN] VARCHAR (255) NULL,
[Notes] VARCHAR (255) NULL,
[BookID] INT IDENTITY (1, 1) NOT NULL,
CONSTRAINT [PK_textBooks] PRIMARY KEY CLUSTERED ([BookID] ASC),
CONSTRAINT [FK_textBooks_ToTable] FOREIGN KEY ([BookID]) REFERENCES [BookCourse]([BookID])
);
Here is my Course Table
CREATE TABLE [dbo].[Course] (
[CourseID] VARCHAR (50) NOT NULL,
[CourseTitle] VARCHAR (255) NULL,
[cID] INT IDENTITY (1, 1) NOT NULL,
CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED ([cID] ASC),
CONSTRAINT [FK_Course_ToTable] FOREIGN KEY ([cID]) REFERENCES [BookCourse]([cID])
);
Table Adapters with Insert:
JUTDMSTableAdapters.textBooksTableAdapter bookTableAdapter;
bookTableAdapter = new JUTDMSTableAdapters.textBooksTableAdapter();
JUTDMSTableAdapters.CourseTableAdapter courseTableAdapter;
courseTableAdapter = new JUTDMSTableAdapters.CourseTableAdapter();
courseTableAdapter.Insert( CourseID: txtCourseID.Text, CourseTitle: txtCourseTitle.Text);
bookTableAdapter.Insert( thirteenISBN: txt13ISBN.Text, CourseID: txtCourseID.Text, BookTitle: txtBookTitle.Text, Ancillary: txtAncillary.Text,
BookActive: txtBookActive.Text, ActiveDate: txtActiveDate.Text, InactiveDate: txtInactiveDate.Text, Author: txtAuthor.Text,
Imprint: txtImprint.Text, Publisher: txtPublisher.Text, EditionAndDate: txtEditionDate.Text,
VendorISBN: vendISBN, tenISBN: txt10ISBN.Text, ebookAvailable: txtEBookAvailable.Text, eISBN: txtEISBN.Text, Notes: txtNotes.Text);
I figured in my Course table adapter insert I wouldn't have to add the cID column seeing as it is auto increment but I get this error:
Additional information: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Course_ToTable". The conflict occurred in database "F:\HUTDMS V-2.0\HUTDMS V-2.0\APP_DATA\HUTDMS.MDF", table "dbo.BookCourse", column 'cID'.
BookID in the textbook table is autoincrement
cID in the Course table is autoincrement
BookCourseID in the BookCourse table is autoincrement.
For many-to-many relationship you need to use three tables, Book table, Course table and then intermediate table - BookCourse table. Book table refers BookCourse, Course Table refers BookCourse. There are NOT direct references between Book and Course tables
You first add book into Book table, then Course into Course table, finally you add the pair (CourseID, BookID) into BookCourse table.
As for BookCourse table, you may add composite primary key (CourseID, BookID), or add identity key BookCourseID, but if latter then you need to make sure there are no duplicates - you can create an unique constraint.
https://en.wikipedia.org/wiki/Many-to-many_(data_model)

Comment Count on Entry Table (SQL Query)

It may be a simple/specific question but I really need help on that. I have two tables: Entry and Comment in a SQL Server database. I want to show comment count in entry table. And of course comment count will increase when a comment is added. Two tables are connected like this:
Comment.EntryId = Entry.Id
Entry table:
CREATE TABLE [dbo].[Entry] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Subject] NVARCHAR (MAX) NOT NULL,
[Content] NVARCHAR (MAX) NOT NULL,
[Type] NVARCHAR (50) NOT NULL,
[SenderId] NVARCHAR (50) NOT NULL,
[Date] DATE NOT NULL,
[Department] NVARCHAR (50) NULL,
[Faculty] NVARCHAR (50) NULL,
[ViewCount] INT DEFAULT ((0)) NOT NULL,
[SupportCount] INT DEFAULT ((0)) NOT NULL,
[CommentCount] INT DEFAULT ((0)) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
Comment table:
CREATE TABLE [dbo].[Comment] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[EntryId] INT NOT NULL,
[SenderId] NVARCHAR (50) NOT NULL,
[Date] DATETIME NOT NULL,
[Content] NVARCHAR (MAX) NOT NULL,
[SupportCount] INT NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
I am showing the entries in a gridview in codebehind (c#). The question is this, what should I write as a query to do this most efficiently? Thanks for help.
Try this:
select e.Id,e.date,count(*) as NumComments
from Entry e
join comment c on c.entryId=e.id
group by e.id,e.date
If there might be no comments, try the following
select e.Id,e.date,count(c.entryId) as NumComments
from Entry e
left join comment c on c.entryId=e.id
group by e.id,e.date
You can use left join for that purpose. Kindly me more specific with what fields you want in gridview
And why do you want commentcount in table (most tables have that 1-many relation and we didn't use that). If you keep that in table you have to update entry table every time when comment is made.

Primary key value doesn't increment auto in Entity framwork database

I am sure m missing something really small but i am having issue of Primary value auto incremental. I have creates two simple table and I have adopt Existing database model first approach by using Entity Framework 5. I simple adding values in table from console program.
My issue is code works fine for first time, but crashes if i try to add more value by running whole app again and i found the reason; the EF doesn't increment primary index automatically.
table
CREATE TABLE [dbo].[Book_Titles] (
[Book_ID] INT NOT NULL,
[Title] NVARCHAR (150) NOT NULL,
PRIMARY KEY CLUSTERED ([Book_ID] ASC)
);
CREATE TABLE [dbo].[Books_Authors] (
[Author_Id] INT NOT NULL,
[Author_Name] NVARCHAR (150) NOT NULL,
[Book_ID] INT NULL,
PRIMARY KEY CLUSTERED ([Author_Id] ASC),
FOREIGN KEY ([Book_ID]) REFERENCES [dbo].[Book_Titles] ([Book_ID])
);
Console program
namespace Database_First_01
{
class Program
{
static void Main(string[] args)
{
using (var db = new BooksContext())
{
var book = new Book_Titles()
{
Title ="EF ",
};
var author = new Books_Authors()
{
Author_Name = "me!",
};
book.Books_Authors.Add(author);
db.Book_Titles.Add(book);
db.SaveChanges();
}
}
}
}
many thanks in advance.
Try this
CREATE TABLE [dbo].[Book_Titles] (
[Book_ID] INT IDENTITY(1,1) NOT NULL,
[Title] NVARCHAR (150) NOT NULL,
PRIMARY KEY CLUSTERED ([Book_ID] ASC)
);
Define Identity on Column
Same as other if you want.
Microsoft SQL Server uses the IDENTITY keyword to perform an auto-increment feature. and its missing in your case.
You can use IDENTITY property in different cases
Its used with the CREATE TABLE
and ALTER TABLE Transact-SQL statements.
so if you have already created the table ( and it has data ) you may just alter like as follow.
ALTER TABLE (yourTable) ADD NewColumn INT IDENTITY(1,1)
ALTER TABLE (yourTable) DROP COLUMN OldColumnName
sp_rename 'yourTable.NewColumn', 'OldColumnName', 'COLUMN'
and it will save your data in the existing table.
Hope it will help

Many-To-Many Query with Linq-To-NHibernate

Ok guys (and gals), this one has been driving me nuts all night and I'm turning to your collective wisdom for help.
I'm using Fluent Nhibernate and Linq-To-NHibernate as my data access story and I have the following simplified DB structure:
CREATE TABLE [dbo].[Classes](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[StartDate] [datetime2](7) NOT NULL,
[EndDate] [datetime2](7) NOT NULL,
CONSTRAINT [PK_Classes] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
CREATE TABLE [dbo].[Sections](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[ClassId] [bigint] NOT NULL,
[InternalCode] [varchar](10) NOT NULL,
CONSTRAINT [PK_Sections] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
CREATE TABLE [dbo].[SectionStudents](
[SectionId] [bigint] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_SectionStudents] PRIMARY KEY CLUSTERED
(
[SectionId] ASC,
[UserId] ASC
)
CREATE TABLE [dbo].[aspnet_Users](
[ApplicationId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
[UserName] [nvarchar](256) NOT NULL,
[LoweredUserName] [nvarchar](256) NOT NULL,
[MobileAlias] [nvarchar](16) NULL,
[IsAnonymous] [bit] NOT NULL,
[LastActivityDate] [datetime] NOT NULL,
PRIMARY KEY NONCLUSTERED
(
[UserId] ASC
)
I omitted the foreign keys for brevity, but essentially this boils down to:
A Class can have many Sections.
A Section can belong to only 1 Class but can have many Students.
A Student (aspnet_Users) can belong to many Sections.
I've setup the corresponding Model classes and Fluent NHibernate Mapping classes, all that is working fine.
Here's where I'm getting stuck. I need to write a query which will return the sections a student is enrolled in based on the student's UserId and the dates of the class.
Here's what I've tried so far:
1.
var sections = (from s in this.Session.Linq<Sections>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.First(f => f.UserId == userId) != null
select s);
2.
var sections = (from s in this.Session.Linq<Sections>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.Where(w => w.UserId == userId).FirstOrDefault().Id == userId
select s);
Obviously, 2 above will fail miserably if there are no students matching userId for classes the current date between it's start and end dates...but I just wanted to try.
The filters for the Class StartDate and EndDate work fine, but the many-to-many relation with Students is proving to be difficult. Everytime I try running the query I get an ArgumentNullException with the message:
Value cannot be null.
Parameter name: session
I've considered going down the path of making the SectionStudents relation a Model class with a reference to Section and a reference to Student instead of a many-to-many. I'd like to avoid that if I can, and I'm not even sure it would work that way.
Thanks in advance to anyone who can help.
Ryan
For anyone who cares, it looks like the following might work in the future if Linq-To-NHibernate can support subqueries (or I could be totally off-base and this could be a limitation of the Criteria API which is used by Linq-To-NHibernate):
var sections = (from s in session.Linq<Section>()
where s.Class.StartDate <= DateTime.UtcNow
&& s.Class.EndDate > DateTime.UtcNow
&& s.Students.First(f => f.UserId == userId) != null
select s);
However I currently receive the following exception in LINQPad when running this query:
Cannot use subqueries on a criteria
without a projection.
So for the time being I've separated this into 2 operations. First get the Student and corresponding Sections and then filter that by Class date. Unfortunately, this results in 2 queries to the database, but it should be fine for my purposes.

Categories

Resources