#asp.net-mvc-3 #entity-framework #entity-framework-4 #entity-framework-4.1
#asp.net-mvc-3 #entity-framework #сущность-фреймворк-4 #сущность-фреймворк-4.1 #entity-framework-4 #entity-framework-4.1
Вопрос:
Поэтому я решил использовать подход code first / DbContext, но у меня уже есть существующий файл базы данных. Ничего сложного, поэтому я думаю, что могу просто создать класс контейнера, производный от DbContext, с DbSets для соответствующих POCO, создать строку подключения к моей базе данных, и я должен быть установлен. Однако я считаю, что у меня возникают трудности с правильным объявлением свойств в моих классах сущностей, поскольку я получаю ошибки при попытке доступа к объекту через навигационные свойства. Обычно сообщаю мне, Object reference not set to an instance of an object
когда я пытаюсь context.Products.Find(1).Category.CATNAME;
и т.д. Также безуспешно пытался объявить свойства коллекции с помощью ключевого слова virtual.
Некоторые особенности схемы базы данных:
В таблице Categories PCATID является внешним ключом к CategoryID в той же таблице Categories и может быть нулевым.
Как CategoryID, так и RootCategoryID в таблице Products могут иметь значение null и оба являются внешними ключами для CategoryID в таблице Categories.
В данный момент я тестирую вещи, но в конечном итоге буду устанавливать для многих полей ненулевые типы.
Вот мои entity POCO и класс контейнера entity Dbset:
public class Category
{
[Key]
public int CategoryID { get; set; }
public string CATNAME { get; set; }
public int PCATID { get; set; }
public ICollection<Category> Categories { get; set; }
public ICollection<Product> Products { get; set; }
}
public class Product
{
[Key]
public int ProductID { get; set; }
public int CategoryID { get; set; }
public int RootCategoryID { get; set; }
public string Name { get; set; }
public string ShortDescription { get; set; }
public string LongDescription { get; set; }
public string Keywords { get; set; }
public decimal ListPrice { get; set; }
public Category Category { get; set; }
}
public class EFDbContext: DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
}
Комментарии:
1. Можете ли вы опубликовать скриншот со схемой существующей базы данных (например, из SQL Management Studio) и linq-запросом, который вы выполняете?
Ответ №1:
Вам нужно создать PCATID
свойство, допускающее значение null, поскольку вы сказали, что оно может быть null. Сделайте все эти навигационные свойства и свойства коллекции виртуальными. EF не сможет определить иерархию категорий, поэтому вам придется использовать либо атрибуты, либо fluent API для ее настройки.
public class Category
{
[Key]
public int CategoryID { get; set; }
public string CATNAME { get; set; }
[ForeignKey("ParentCategory")]
public int? PCATID { get; set; }
[InverseProperty("Categories")]
public virtual Category ParentCategory { get; set; }
[InverseProperty("ParentCategory")]
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Ответ №2:
Требования к созданию прокси-серверов POCO
Все выглядит готовым для POCO, но отложенная загрузка на данный момент не устранена. По умолчанию LL включен, но для того, чтобы включить отложенную загрузку, свойство Category должно быть виртуальным (создается прокси, который перехватывает ссылку и загружает данные). Если вы не хотите отложенной загрузки, отключите ее в своем конструкторе EFDbContext.
Итак, ваши варианты:
public virtual Category Category { get; set; }
или
public class EFDbContext: DbContext
{
public static EFDbContext()
{
LazyLoadingEnabled = false
}
...
}
Вы, вероятно, захотите сделать первое…
Ответ №3:
Вы уверены, что действительно хотите сначала использовать Code? Или вы просто хотите использовать DbContext и DbSet? Вы можете получить те же преимущества с Database First, используя DbContext и DbSet. Поскольку у вас уже есть база данных, это, как правило, намного проще.
Смотрите: http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-model-amp-database-first-walkthrough.aspx
Единственное различие между Code First и Database First с DbContext заключается в том, что Code first использует модель fluent mapping, в то время как Database First использует файл .edmx. Поддерживать .edmx намного проще с существующей базой данных.
Если вы связаны и полны решимости сначала использовать Code, тогда я предлагаю получить Entity Framework Power Tools CTP1 и сначала выполнить обратное проектирование вашей базы данных для кода.
Ответ №4:
Я согласен с @Eranga по поводу класса Category
( 1 к @Eranga).
public class Category {
[Key]
public int CategoryID { get; set; }
public string CATNAME { get; set; }
[ForeignKey("ParentCategory")]
public int? PCATID { get; set; }
[InverseProperty("Categories")]
public virtual Category ParentCategory { get; set; }
[InverseProperty("ParentCategory")]
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
И у вас также есть проблема с вашим запросом Linq:
context.Products.Find(1).Category.CATNAME;
EF возвращает данные только из таблиц, которые вы запрашиваете с Include
или вы используете эти таблицы в функциях.
С этим кодом все работает:
db.Products
.Include(p => p.Category) // here I demand to load data from Category table
.First(p => p.ProductID == 3)
.Category
.CATNAME;