I have an N+1 problem and I'm not sure how to solve it.
A fully-reproducible sample may be found at the bottom of this question. So if you are willing, please create the database, set up the NUnit test and all the accompanying classes, and try to eliminate the N+1 locally. This is the anonymized version of a real problem I encountered. For all you know, this code is crucial in helping launch the next space shuttle to the moon. I won't deny it if asked.
To summarize the problem: I am trying to query a table structure that is drawn below. The only weird thing to note about this table structure is that questions have choices, which then have sub-questions, which then have sub-choices. You can assume only 2 levels of question->choice->question->choice.
SiteSurveyQuestion
|
+---Site
|
+---Survey
|
+---Question
|
+---Choice
+---Choice
+---Choice
|
+---Question
+---Question
+---Question
|
+---Choice
+---Choice
+---Choice
I've tried everything I know to try.
In the mappings, I have tried a bunch of referencing fields as .Not.LazyLoad()
to no real success.
I have also tried modifying the query by adding many combinations of .Fetch()
and .FetchMany()
and .ThenFetchMany()
and even tried running multiple .ToFuture()
queries. These do make real changes to the SQL query, but not the final result I'm looking for.
The query as it is boiled down, is "get me a list of all questions for this survey on this site, including all sub-questions". Here is the query:
using (var session = sessionFactory.OpenSession())
{
var questionsForSurvey = session.Query<SiteSurveyQuestion>()
.Where(x => x.Site.Id == 1 && x.Survey.Id == 1)
.ToArray();
}
So to finally ask the question: how can I fix this N+1 problem? I would be happy with any of the following
- (Preferred) A fix in the class mappings to eager load everything
- (2nd choice) Sprinking the Query with fetch's or query hints using the LINQ provider
- (3rd choice) mix of the above
- (4th choice) being told it's impossible and a limitation of NHibernate
- (5th choice) Solution in HQL
I do not want an HQL solution because I won't learn anything about what I'm doing wrong with my mapping and/or querying - I feel like I'm missing something fundamental, and I don't even know where to look.
Sample instructions:
- Copy and paste the SQL setup script into your local SQL Server instance, run it.
- Create a test project (or if you're lazy, use your existing test project) and add the nuget packages for NHibernate and Fluent NHibernate to the project.
- Run the test. You should see:
- Generated SQL run by NHibernate
- Output from the test.
- Fix mappings/query until N+1 is gone - you will know when you see first a bunch of SQL scripts outputted, then:
```
Site: Site1 Survey: SurveyAboutCats Q: Own A Cat?
o Yes
Q: How many cats did you feed yesterday?
o 1
o 2-5
o 6-10
o 11-20
o 20+
o 100+
Q: How much do you spend on cats annually?
o 0-100
o 100-500
o 500-2000
o 2000+
o No
Q: No cats? What is wrong with you?
o I am sorry
Site: Site1 Survey: SurveyAboutCats Q: Own A Dog?
o Yes
o No
Full sample:
/*
Nuget packages:
<package id="FluentNHibernate" version="1.3.0.733" targetFramework="net40" />
<package id="NHibernate" version="3.3.3.4001" targetFramework="net45" />
<package id="NUnit" version="2.6.2" targetFramework="net40" />
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Conventions.Helpers;
using FluentNHibernate.Mapping;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Linq;
using NUnit.Framework;
namespace StackOverflow.CryForHelp
{
[TestFixture]
public class NHibernateMappingTests
{
[Test]
public void ShouldMapEntitiesWithoutNPlusOneIssue()
{
//Arrange
var connectionString = "Data Source=(local);Initial Catalog=NinetyNineProblemsAndAnNPlusOne;Integrated Security=SSPI;";
Configuration applicationConfiguration = new Configuration();
applicationConfiguration.SetProperty("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
applicationConfiguration.SetProperty("dialect", "NHibernate.Dialect.MsSql2008Dialect");
applicationConfiguration.SetProperty("connection.driver_class", "NHibernate.Driver.SqlClientDriver");
applicationConfiguration.SetProperty("default_schema", "dbo");
applicationConfiguration.SetProperty("format_sql", "format_sql");
applicationConfiguration.SetProperty("show_sql", "true");
applicationConfiguration.SetProperty("generate_statistics", "true");
applicationConfiguration.Configure();
Configuration fluentConfiguration = null;
ISessionFactory sessionFactory = Fluently.Configure(applicationConfiguration)
.Mappings(m =>
{
m.FluentMappings.Conventions.Setup(x => x.Add(AutoImport.Never()));
m.FluentMappings.AddFromAssembly(Assembly.GetAssembly(GetType()));
})
.ExposeConfiguration(c => fluentConfiguration = c)
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString))
.BuildSessionFactory();
var mappings = fluentConfiguration.ClassMappings;
//Act + Assert that we please don't create N+1 queries
using (var session = sessionFactory.OpenSession())
{
var questionsForSurvey = session.Query<SiteSurveyQuestion>()
.Where(x => x.Site.Id == 1 && x.Survey.Id == 1)
.ToArray();
foreach (var question in questionsForSurvey)
{
Console.WriteLine("Site: {0} Survey: {1} Q: {2}", question.Site.Name, question.Survey.Name, question.Question.InternalName);
foreach (var choice in question.Question.Choices)
{
Console.WriteLine("\t> " + choice.InternalName);
foreach (var subQuestion in choice.Questions)
{
Console.WriteLine("\t\tQ: " + subQuestion.InternalName);
foreach (var subChoice in subQuestion.Choices)
Console.WriteLine("\t\t\t> " + subChoice.InternalName);
}
}
}
}
}
}
public class Site
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class Survey
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class SiteSurvey
{
public virtual Site Site { get; set; }
public virtual Survey Survey { get; set; }
public virtual string Status { get; set; }
public virtual string Name { get; set; }
public virtual bool Equals(SiteSurvey other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Site.Id == other.Site.Id && Survey.Id == other.Survey.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((SiteSurvey) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Survey.Id * 397) ^ Site.Id;
}
}
}
public class SiteSurveyQuestion
{
public virtual Site Site { get; set; }
public virtual Survey Survey { get; set; }
public virtual Question Question { get; set; }
public virtual bool IsActive { get; set; }
public virtual bool Equals(SiteSurveyQuestion other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Site.Id == other.Site.Id && Survey.Id == other.Survey.Id && Question.Id == other.Question.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((SiteSurveyQuestion) obj);
}
public override int GetHashCode()
{
unchecked
{
return Question.Id ^ (((Survey.Id * 397) ^ Site.Id) * 397);
}
}
}
public class Question
{
public virtual int Id { get; set; }
public virtual string InternalName { get; set; }
public virtual bool IsActive { get; set; }
public virtual IEnumerable<Choice> Choices { get; set; }
}
public class Choice
{
public virtual int Id { get; set; }
public virtual string InternalName { get; set; }
public virtual bool IsActive { get; set; }
public virtual IEnumerable<Question> Questions { get; set; }
}
public class SurveyMap : ClassMap<Survey>
{
public SurveyMap()
{
Table("Surveys");
Id(x => x.Id, "SurveyId").GeneratedBy.Identity().UnsavedValue(0);
Map(x => x.Name).Not.Nullable();
}
}
public class SiteMap : ClassMap<Site>
{
public SiteMap()
{
Table("Sites");
Id(x => x.Id, "SiteId").GeneratedBy.Identity().UnsavedValue(0);
Map(x => x.Name, "Name").Not.Nullable();
}
}
public class SiteSurveyMap : ClassMap<SiteSurvey>
{
public SiteSurveyMap()
{
Table("SiteSurveys");
CompositeId()
.KeyReference(x => x.Site, "SiteId")
.KeyReference(x => x.Survey, "SurveyId");
Map(x => x.Status).Not.Nullable();
Map(x => x.Name).Not.Nullable();
}
}
public class SiteSurveyQuestionMap : ClassMap<SiteSurveyQuestion>
{
public SiteSurveyQuestionMap()
{
Table("SiteSurveyQuestions");
CompositeId()
.KeyReference(x => x.Site, "SiteId")
.KeyReference(x => x.Survey, "SurveyId")
.KeyReference(x => x.Question, "QuestionId");
Map(x => x.IsActive, "ActiveFlag").Not.Nullable();
}
}
public class QuestionMap : ClassMap<Question>
{
public QuestionMap()
{
Table("Questions");
Id(x => x.Id, "QuestionId").GeneratedBy.Identity().UnsavedValue(0);
Map(x => x.InternalName);
Map(x => x.IsActive, "ActiveFlag");
HasMany(x => x.Choices).KeyColumn("QuestionId").AsBag().Cascade.AllDeleteOrphan().Inverse().Not.LazyLoad();
}
}
public class ChoiceMap : ClassMap<Choice>
{
public ChoiceMap()
{
Table("Choices");
Id(x => x.Id, "ChoiceId").GeneratedBy.Identity().UnsavedValue(0);
Map(x => x.InternalName);
Map(x => x.IsActive, "ActiveFlag");
HasMany(x => x.Questions)
.KeyColumn("ChoiceId")
.AsBag()
.Cascade
.AllDeleteOrphan()
.Inverse();
}
}
}
/*
use [master]
GO
CREATE DATABASE [NinetyNineProblemsAndAnNPlusOne]
GO
USE [NinetyNineProblemsAndAnNPlusOne]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Sites](
[SiteId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NOT NULL,
CONSTRAINT [XPKSites] PRIMARY KEY CLUSTERED
(
[SiteId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [XAK1Sites] UNIQUE NONCLUSTERED
(
[Name] 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
CREATE TABLE [dbo].[Surveys](
[SurveyId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](500) NOT NULL,
[Status] [varchar](12) NOT NULL,
[SurveyTypeId] [int] NOT NULL,
CONSTRAINT [XPKSurveys] PRIMARY KEY CLUSTERED
(
[SurveyId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [XAK1Surveys] UNIQUE NONCLUSTERED
(
[Name] 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
CREATE TABLE [dbo].[SiteSurveys](
[SiteId] [int] NOT NULL,
[SurveyId] [int] NOT NULL,
[Name] [varchar](500) NOT NULL,
[Status] [varchar](12) NOT NULL,
CONSTRAINT [XPKSiteSurveys] PRIMARY KEY CLUSTERED
(
[SiteId] ASC,
[SurveyId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [XAK1SiteSurveys] UNIQUE NONCLUSTERED
(
[SiteId] ASC,
[SurveyId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [XAK2SiteSurveys] UNIQUE NONCLUSTERED
(
[SiteId] ASC,
[Name] 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
CREATE TABLE [dbo].[SiteSurveyQuestions](
[SiteId] [int] NOT NULL,
[SurveyId] [int] NOT NULL,
[QuestionId] [int] NOT NULL,
[SurveyQuestionTypeId] [int] NULL,
[ActiveFlag] [bit] NOT NULL,
[IsRequired] [bit] NOT NULL,
CONSTRAINT [XPKSurveyQuestions] PRIMARY KEY CLUSTERED
(
[SurveyId] ASC,
[QuestionId] 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
CREATE TABLE [dbo].[Questions](
[QuestionId] [int] IDENTITY(1,1) NOT NULL,
[InternalName] [varchar](100) NOT NULL,
[ChoiceId] [int] NULL,
[ActiveFlag] [bit] NOT NULL,
CONSTRAINT [XPKQuestions] PRIMARY KEY CLUSTERED
(
[QuestionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [XAK1QuestionsInternalName] UNIQUE NONCLUSTERED
(
[InternalName] ASC,
[ChoiceId] 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
CREATE TABLE [dbo].[Choices](
[ChoiceId] [int] IDENTITY(1,1) NOT NULL,
[QuestionId] [int] NOT NULL,
[InternalName] [varchar](100) NOT NULL,
[ActiveFlag] [bit] NOT NULL,
CONSTRAINT [XPKChoices] PRIMARY KEY CLUSTERED
(
[ChoiceId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [XAKChoiceIdQuestionId] UNIQUE NONCLUSTERED
(
[ChoiceId] ASC,
[QuestionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [XAKChoiceInternalName] UNIQUE NONCLUSTERED
(
[QuestionId] ASC,
[InternalName] 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].[Surveys] WITH CHECK ADD CONSTRAINT [VRSurveyStatuses_Surveys] CHECK (([Status]='Live' OR [Status]='NotLive' OR [Status]='Discontinued'))
GO
ALTER TABLE [dbo].[Surveys] CHECK CONSTRAINT [VRSurveyStatuses_Surveys]
GO
ALTER TABLE [dbo].[SiteSurveys] WITH CHECK ADD CONSTRAINT [R289] FOREIGN KEY([SurveyId])
REFERENCES [dbo].[Surveys] ([SurveyId])
GO
ALTER TABLE [dbo].[SiteSurveys] CHECK CONSTRAINT [R289]
GO
ALTER TABLE [dbo].[SiteSurveys] WITH CHECK ADD CONSTRAINT [R303] FOREIGN KEY([SiteId])
REFERENCES [dbo].[Sites] ([SiteId])
GO
ALTER TABLE [dbo].[SiteSurveys] CHECK CONSTRAINT [R303]
GO
ALTER TABLE [dbo].[SiteSurveys] WITH CHECK ADD CONSTRAINT [VRSurveyStatuses_SiteSurveys] CHECK (([Status]='Live' OR [Status]='NotLive' OR [Status]='Discontinued'))
GO
ALTER TABLE [dbo].[SiteSurveys] CHECK CONSTRAINT [VRSurveyStatuses_SiteSurveys]
GO
ALTER TABLE [dbo].[SiteSurveyQuestions] WITH CHECK ADD CONSTRAINT [QuestionsToSurveyQuestions] FOREIGN KEY([QuestionId])
REFERENCES [dbo].[Questions] ([QuestionId])
GO
ALTER TABLE [dbo].[SiteSurveyQuestions] CHECK CONSTRAINT [QuestionsToSurveyQuestions]
GO
ALTER TABLE [dbo].[SiteSurveyQuestions] WITH CHECK ADD CONSTRAINT [SurveysToSurveyQuestions] FOREIGN KEY([SurveyId])
REFERENCES [dbo].[Surveys] ([SurveyId])
GO
ALTER TABLE [dbo].[SiteSurveyQuestions] CHECK CONSTRAINT [SurveysToSurveyQuestions]
GO
ALTER TABLE [dbo].[Questions] WITH CHECK ADD CONSTRAINT [R409] FOREIGN KEY([ChoiceId])
REFERENCES [dbo].[Choices] ([ChoiceId])
GO
ALTER TABLE [dbo].[Choices] WITH CHECK ADD CONSTRAINT [R408] FOREIGN KEY([QuestionId])
REFERENCES [dbo].[Questions] ([QuestionId])
GO
ALTER TABLE [dbo].[Choices] CHECK CONSTRAINT [R408]
GO
SET ANSI_PADDING OFF
GO
GO
SET IDENTITY_INSERT [dbo].[Sites] ON
INSERT [dbo].[Sites] ([SiteId], [Name]) VALUES (1, N'Site1')
INSERT [dbo].[Sites] ([SiteId], [Name]) VALUES (2, N'Site2')
SET IDENTITY_INSERT [dbo].[Sites] OFF
SET IDENTITY_INSERT [dbo].[Surveys] ON
INSERT [dbo].[Surveys] ([SurveyId], [Name], [Status], [SurveyTypeId]) VALUES (1, N'SurveyAboutCats', N'Live', 0)
INSERT [dbo].[Surveys] ([SurveyId], [Name], [Status], [SurveyTypeId]) VALUES (2, N'Crime Survey', N'Live', 0)
SET IDENTITY_INSERT [dbo].[Surveys] OFF
SET IDENTITY_INSERT [dbo].[Questions] ON
INSERT [dbo].[Questions] ([QuestionId], [InternalName], [ChoiceId], [ActiveFlag]) VALUES (1, N'Own A Cat?', NULL, 1)
INSERT [dbo].[Questions] ([QuestionId], [InternalName], [ChoiceId], [ActiveFlag]) VALUES (2, N'Own A Dog?', NULL, 1)
INSERT [dbo].[Questions] ([QuestionId], [InternalName], [ChoiceId], [ActiveFlag]) VALUES (3, N'Witnessed any crimes recently?', NULL, 1)
INSERT [dbo].[Questions] ([QuestionId], [InternalName], [ChoiceId], [ActiveFlag]) VALUES (4, N'Committed any crimes yourself recently?', NULL, 1)
SET IDENTITY_INSERT [dbo].[Questions] OFF
SET IDENTITY_INSERT [dbo].[Choices] ON
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (1, 1, N'Yes', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (2, 1, N'No', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (3, 2, N'Yes', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (4, 2, N'No', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (5, 3, N'Yes', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (6, 3, N'Yes but I ain''t no snitch', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (7, 4, N'No', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (8, 4, N'I plead the fifth', 1)
SET IDENTITY_INSERT [dbo].[Choices] OFF
SET IDENTITY_INSERT [dbo].[Questions] ON
INSERT [dbo].[Questions] ([QuestionId], [InternalName], [ChoiceId], [ActiveFlag]) VALUES (6, N'No cats? What is wrong with you?', 2, 1)
INSERT [dbo].[Questions] ([QuestionId], [InternalName], [ChoiceId], [ActiveFlag]) VALUES (7, N'How many cats did you feed yesterday?', 1, 1)
INSERT [dbo].[Questions] ([QuestionId], [InternalName], [ChoiceId], [ActiveFlag]) VALUES (8, N'How much do you spend on cats annually?', 1, 1)
SET IDENTITY_INSERT [dbo].[Questions] OFF
SET IDENTITY_INSERT [dbo].[Choices] ON
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (9, 6, N'I am sorry', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (10, 7, N'1', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (11, 7, N'2-5', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (12, 7, N'6-10', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (13, 7, N'11-20', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (14, 7, N'20+', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (15, 7, N'100+', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (16, 8, N'0-100', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (17, 8, N'100-500', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (18, 8, N'500-2000', 1)
INSERT [dbo].[Choices] ([ChoiceId], [QuestionId], [InternalName], [ActiveFlag]) VALUES (19, 8, N'2000+', 1)
SET IDENTITY_INSERT [dbo].[Choices] OFF
INSERT [dbo].[SiteSurveys] ([SiteId], [SurveyId], [Name], [Status]) VALUES (1, 1, N'Site #1 Cat Survey', N'Live')
INSERT [dbo].[SiteSurveys] ([SiteId], [SurveyId], [Name], [Status]) VALUES (1, 2, N'Site #1 Crime Survey', N'Live')
INSERT [dbo].[SiteSurveys] ([SiteId], [SurveyId], [Name], [Status]) VALUES (2, 1, N'Site #2 Cat Survey', N'Live')
INSERT [dbo].[SiteSurveys] ([SiteId], [SurveyId], [Name], [Status]) VALUES (2, 2, N'Site #2 Crime Survey', N'Live')
INSERT [dbo].[SiteSurveyQuestions] ([SiteId], [SurveyId], [QuestionId], [SurveyQuestionTypeId], [ActiveFlag], [IsRequired]) VALUES (1, 1, 1, 0, 1, 0)
INSERT [dbo].[SiteSurveyQuestions] ([SiteId], [SurveyId], [QuestionId], [SurveyQuestionTypeId], [ActiveFlag], [IsRequired]) VALUES (1, 1, 2, 0, 1, 0)
GO
USE [master]
GO
-- */