Основной список перечислений EF

#c# #.net-core #entity-framework-core #blazor

#c# #.net-ядро #сущность-основа-ядро #блейзор

Вопрос:

Я работаю над небольшим приложением для организации бронирования отелей в Entity Framework Core. Мне нужно добавить информацию о количестве и типе кроватей в каждой комнате. Я подумал и решил, что список перечислений будет лучше, чем хранить его в отдельной таблице. Но я не знаю, как этого добиться

 public enum Bed
{
    Single = 1,
    Double = 2,
}

public class Room : IEntity
{
   [Key]
   public int Id { get; set; }
        
   public string RoomIdentifier { get; set; }
   public ICollection<Bed> Beds { get; set; }
        
   public int Floor { get; set; }
   public double Price { get; set; }

   public bool IsFree { get; set; }
   public bool IsOutOfService { get; set; }
   public bool ShouldBeCleaned { get; set; }
        
   public ICollection<RoomReservation> RoomReservations { get; set; }
}
 

Возможно ли это сделать? Я также думал сохранить его в виде строки, например (1,2,1,2), а затем проанализировать его, чтобы получить количество и тип кроватей в комнате. Большое спасибо за помощь!

Комментарии:

1. По умолчанию список перечислений будет храниться в отдельной таблице. таким образом, строка идентификаторов, проанализированная обратно в список, будет пользовательским сериализатором

2. Перечисления хранятся в базе данных в виде целых чисел. Преобразователи значений используются для преобразования между типом перечисления и его числовым эквивалентом. См. docs.microsoft.com/en-us/ef/core/modeling/value-conversions

3. @RobertHarvey Этого было бы достаточно, если бы у меня было одно значение enum, но в моем случае у меня есть список перечислений для каждого объекта room, я не знаю, сработает ли это.

4. Я не понимаю, как список перечислений будет отличаться от списка любого другого объекта.

5. Не используя отдельную таблицу, вы не получаете ничего, кроме проблем — нестандартное обнаружение изменений, невозможность выполнения критериев запроса на стороне сервера для такого «столбца» и т. Д. Хранение значений в строке, разделенной запятыми, ничем не лучше, чем хранение дат / чисел в строке вместо собственного типа данных. В настоящее время таблицы базы данных (особенно когда они управляются с помощью миграции кода ORM) бесплатны (в основном бесплатно), просто используйте их и не тратьте свое время. Я почти уверен, что следующий вопрос, который вы отправите через несколько дней после этого, будет «как найти комнаты с определенным количеством и типом кроватей, используя LINQ и EF Core», без хорошего ответа

Ответ №1:

Вот пример с составленными именами объектов, надеюсь, это поможет.

В OnModelCreating:

 modelBuilder.Entity<Room>()
        .Property(e => e.BedList)
        .HasConversion(
            v => string.Join(',', v),
            v => v.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<Bed>())
        .Metadata.SetValueComparer(valueComparer);
 

Вам нужно будет создать свой собственный пример valuecomparer ниже
для списка:

 var valueComparer = new ValueComparer<ICollection<string>>(
                    (c1, c2) => c1.SequenceEqual(c2),
                    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
                    c => (ICollection<string>)c.ToHashSet());
 

Комментарии:

1. Зачем мне нужно иметь ValueComparer ? Здесь все работает нормально и без него.

2. Отслеживание изменений @RogerioSchmitt может определять изменение столбца и выполнять запись, когда это не требуется, без средства сравнения значений. но, честно говоря, я не тестировал без.

Ответ №2:

Я неправильно понял вопрос… если вы пытаетесь сохранить список, разделенный запятыми, в одном поле, следуйте примеру Ричарда … или обработайте его вручную в своей логике сопоставления, если она у вас есть.

Приведенный ниже ответ будет дан только в том случае, если вы пытаетесь использовать перечисление вместо таблицы, а не в том случае, если вы пытаетесь поместить несколько значений перечисления в один столбец.


Есть хороший пакет C #, который называется SmartEnum Ardalis Steve Smith. Ссылка на GitHub

Это позволит вам иметь строго типизированное перечисление, но вы можете сохранить его в базе данных в виде строки или целого числа или как вам угодно.

Вот пример:

 public sealed class Bed : SmartEnum<TestEnum>
{
    // static instances of the SmartEnum Bed represents the enumerations
    public static readonly Bed Single = new Bed(name: "Single", value: 1, isPremium: false);
    public static readonly Bed Double = new Bed(name: "Double", value: 2, isPremium: true);


    // example additional property of each enumeration
    public bool IsPremium = false;


    private Bed(string name, int value, bool isPremium) : base(name, value)
    {
        IsPremium = isPremium;
    }
}
 

В приведенном выше примере перечисление подкрепляется int значением. Вы можете подкрепить его строкой, используя : SmartEnum<TestEnum, string> . Он поддерживает неявные приведения и т. Д., Хорошо работает с EF, и вы сможете «перечислять» перечисления по мере необходимости.

Комментарии:

1. Хм. Dapper не требует ничего из этого; вы просто объявляете свое свойство в DTO как тип перечисления, и Dapper автоматически выполняет правильные действия (поле базы данных — an int ).

2. @RobertHarvey о, конечно, это альтернатива — вместо этого решает проблему на уровне домена.

3. Да, я думал, что сохранение этих значений в виде строковых значений было бы лучшим, но другие предложения также очень ценятся

4. Ядро EF также делает это автоматически и поддерживает как хранение (так и запрос) значений перечислений в виде int или string в базе данных, поэтому никаких дополнительных пакетов не требуется.

5. @IvanStoev я в курсе, как я уже говорил ранее… это решает проблему на уровне домена, и у этого есть свои преимущества.