EF Code Сначала не генерируется таблица для ICollection <string>
Я хотел бы получить следующее свойство ICollection в одном из моих классов данных (назовем его "Foo" )
public class Foo
{
[Key]
public int FooId { get; set; }
public string SomeValueOrOther { get; set; }
public virtual ICollection<string> AllowedBars { get; set; }
}
Я могу добавить строковые значения при использовании контекста сущности, но они не "никуда". Другими словами, для представления этой связи не создается таблица, и поэтому значения не сохраняются. То, что я ожидаю, это таблица с двумя столбцами, одна для "FooId" и одна для "AllowedBar", а для EF - автоматическое отображение этого в коллекцию (как это происходит со сложными типами).
Так как этого не происходит, мне пришлось создать класс под названием "FooAllowedBar" с двумя описанными выше свойствами.
Это меня раздражает, потому что это единственный класс типа join, который есть во всем проекте. Это работает, конечно, так что одна ячейка отмечена галочкой, но знает ли кто-нибудь о способе получения EF для создания таблицы для отношения коллекции строк? (Или int, или datetime и т.д.)
Возможно, из небольшой информации, что там на EF (все еще!), что этот тип функциональности еще не поддерживается. Я просто хотел бы подойти к окончательному ответу.
Большое спасибо заранее,
Rob
Ответы
Ответ 1
EF может работать только с классами сущностей. Каждый класс сущности должен иметь определенный первичный ключ, поэтому минимум в вашем сценарии:
public class StringData
{
public int Id { get; set; }
public string Data { get; set; }
}
или хуже
public class StringData
{
[Key]
public string Data { get; set; }
}
Теперь вы можете определить коллекцию StringData для ее сопоставления как связанной таблицы:
public virtual ICollection<StringData> AllowedBars { get; set; }
Ответ 2
Я знаю, что это не лучшая практика во всех случаях, но я думаю, что есть случаи, когда сохранение разделенного запятой списка вашего массива в столбце - хороший способ решить эту проблему.
Условия включают:
- Список не будет длинным
- Вам не нужно искать объекты на основе значений в этом списке
Также может быть хорошей идеей, если у одного объекта есть несколько строковых списков, которые создавали бы множество объединений.
В этих случаях я решил бы это, имея два свойства для списка. Один из них является разделенным запятой списком, используемым EF, а другой - списком, который вы можете использовать при доступе к элементам в списке следующим образом:
[NotMapped]
public List<String> AllowedBars { get; set; }
/// <summary>
/// Comma seperated list of AllowedBars
/// </summary>
public String AllowedBarsList
{
get { return String.Join(",", AllowedBars); }
set
{
if (String.IsNullOrWhiteSpace(value))
{
AllowedBars.Clear();
}
else
{
AllowedBars = value.Split(',').ToList();
}
}
}
Вам нужно инициализировать AllowedBars как пустой список в конструкторе.
Вам не нужно использовать атрибут [NotMapped], так как эта коллекция не будет использоваться в любом случае, но я думаю, что это делает цель более ясной.
Ответ 3
Это не сработает. Причина этого в том, что с реляционными базами данных вы не можете реально сохранить массивы или коллекцию вещей в полях. И поскольку каждое свойство в вашем классе будет сопоставлено с полем базы данных, единственный способ для коллекций - от одного до многих отношений. Поэтому вам нужно присоединиться. Так что это не ограничение EF, а реляционных баз данных.
Есть люди, которые решают это, сохраняя XML или CSV для строковых полей в таблице. Но это считается очень плохой стиль, поэтому не делайте этого. Я рекомендую вам просто принять это соединение. Это никому не повредит.
Ответ 4
Вы не определили свои таблицы классов соответствующим образом. Предположим, у вас есть две таблицы Foo и FooBar. И есть отношения "один ко многим" b/w Foo и FooBar. Затем вы определите классы, как показано ниже.
Foo
public class Foo
{
public int FooId { get; set; }
public string SomeValue { get; set; }
public virtual ICollection<FooBar> FooBars { get; set; }
}
ИмяСтраницы
public class FooBar
{
public int FooBarId { get; set; }
public string SomeProperty { get; set; }
public int FooId { get; set; }
public virtual Foo Foo { get; set; }
}
Это создаст две таблицы, в которых Foo имеет два столбца, а FooBar имеет 3 столбца, включая FooId, изображающие один-на-один между Foo и FooBars