Я пытаюсь создать модель данных, используя EF 4.1 и код в первую очередь.
Мои классы Poco выглядят так:
public abstract class AttributeBase
{
public int Id { get; set; }
public string Name { get; set; }
public string AttributeDescription { get; set; }
public int Length { get; set; }
public bool AllowNull { get; set; }
public bool DisplayInWeb { get; set; }
}
public class StringListAttribute : AttributeBase
{
public ICollection<StringValue> Values { get; set; }
public StringListAttribute()
{
Values = new List<StringValue>();
}
}
public class StringValue
{
public int StringValueId { get; set; }
public string Value { get; set; }
}
Основная идея заключается в том, что StringListAttribute наследуется от класса AttributeBase (другие классы также наследуются от класса AttributeBase, но я не включил их в этот пост)
Класс StringListAttribute имеет коллекцию StringValues. (отношение ноль-ко-многим). В моем классе MyContextExtention я пытаюсь добиться того, чтобы всякий раз, когда мне нужен список объектов AttributeBase из базы данных, я хотел получить все объекты StringListAttribute и заполнить их коллекцию StringValue за один раз. Я не хочу ленивой загрузки. Я хочу получить как можно больше данных в минимально возможном количестве запросов.
Мой класс Context наследуется от DbContext, и я создал метод расширения для моего класса BraArkivContext
public class MyContext : DbContext
{
public DbSet<AttributeBase> Attributes { get; set; }
public MyContext()
{
Configuration.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<StringListAttribute>()
.HasMany(t=>t.Values).WithOptional().WillCascadeOnDelete();
base.OnModelCreating(modelBuilder);
}
}
public static class MyContextExtension
{
private const string Values = "Values";
public static List<AttributeBase> AttributesWithData1(this MyContext context)
{
var attributeBases = new List<AttributeBase>();
var stringListAttributes = context.Attributes.Include(Values).OfType<StringListAttribute>().ToList();
attributeBases.AddRange(stringListAttributes);
return attributeBases;
}
}
Мой тестовый проект (я использую nUnit)) ничего особенного, и он содержит следующие методы:
public class TestHelper
{
public static StringListAttribute CreateStringListAttribute(string name, int listSize)
{
var listAttribute = new StringListAttribute();
listAttribute.Name = name;
for (int i = 0; i < listSize; i++)
{
var attr1 = new StringValue();
attr1.Value = String.Format("StringValue_{0}", i);
listAttribute.Values.Add(attr1);
}
return listAttribute;
}
}
[Test]
public void AttributeBase_GetAllAttributesWithData1()
{
//First add some data to the database
var numberOfObjects = 100;
var name = "StringListAttribute_ReadMultipleStringsListsFromDb_" + Guid.NewGuid().ToString();
var listAttributes = TestHelper.CreateStringLists(name, numberOfObjects);
using (var context = new MyContext())
{
foreach (var stringListAttribute in listAttributes)
{
context.Attributes.Add(stringListAttribute);
}
context.SaveChanges();
}
Stopwatch sw = new Stopwatch()
var attributes = new List<AttributeBase>();
using (var context = new MyContext())
{
sw.Start();
attributes = context.AttributesWithData1().ToList();
sw.Stop();
}
Debug.WriteLine(String.Format("Total time for {0} attributes is: {1}.", attributes.Count, sw.Elapsed));
Assert.IsNotNull(attributes);
}
При запуске метода теста "AttributeBase_GetAllAttributesWithData1" выполняемый оператор sql выглядит следующим образом:
SELECT
[Project1].[Id] AS [Id],
[Project1].[C1] AS [C1],
[Project1].[Name] AS [Name],
[Project1].[AttributeDescription] AS [AttributeDescription],
[Project1].[Length] AS [Length],
[Project1].[AllowNull] AS [AllowNull],
[Project1].[DisplayInWeb] AS [DisplayInWeb],
[Project1].[Document_Id] AS [Document_Id],
[Project1].[C2] AS [C2],
[Project1].[StringValueId] AS [StringValueId],
[Project1].[Value] AS [Value],
[Project1].[StringListAttribute_Id] AS [StringListAttribute_Id]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[AttributeDescription] AS [AttributeDescription],
[Extent1].[Length] AS [Length],
[Extent1].[AllowNull] AS [AllowNull],
[Extent1].[DisplayInWeb] AS [DisplayInWeb],
[Extent1].[Document_Id] AS [Document_Id],
'0X0X' AS [C1],
[Extent2].[StringValueId] AS [StringValueId],
[Extent2].[Value] AS [Value],
[Extent2].[StringListAttribute_Id] AS [StringListAttribute_Id],
CASE WHEN ([Extent2].[StringValueId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
FROM [dbo].[AttributeBases] AS [Extent1]
LEFT OUTER JOIN [dbo].[StringValues] AS [Extent2] ON [Extent1].[Id] = [Extent2].[StringListAttribute_Id]
WHERE [Extent1].[Discriminator] = 'StringListAttribute'
) AS [Project1]
ORDER BY [Project1].[Id] ASC, [Project1].[C2] ASC
Когда я запускаю этот SQL-оператор в SQL Server Management Studio, он довольно быстрый, но Entity Framework очень долго обрабатывает результат и возвращает классы poco, заполненные данными.
Есть ли другой способ моделирования классов AttributeBase, StringListAttribute и StringValue и отношения между ними для уменьшения времени обработки в EF?