Ошибка «Свойство «PPP» List<NNN>» не может быть сопоставлено...» при попытке заполнить модель отношениями в Entity FrameC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Ошибка «Свойство «PPP» List<NNN>» не может быть сопоставлено...» при попытке заполнить модель отношениями в Entity Frame

Сообщение Anonymous »

Сущность:

Код: Выделить всё

using CommonSolution.Entities.Task;
using Microsoft.EntityFrameworkCore;

namespace EntityFramework.Models;

[System.ComponentModel.DataAnnotations.Schema.Table("tasks_custom_folders")]
[Microsoft.EntityFrameworkCore.EntityTypeConfiguration(typeof(TaskCustomFolderModel.Configuration))]
public class TaskCustomFolderModel
{

/* [ Theory ] `Guid.NewGuid()` return the string of 36 characters. See https://stackoverflow.com/a/4458925/4818123 */
[System.ComponentModel.DataAnnotations.Key]
[System.ComponentModel.DataAnnotations.MaxLength(36)]
public string ID { get; set; } = Guid.NewGuid().ToString();

/* ━━━ Title ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
[System.ComponentModel.DataAnnotations.MaxLength(TaskCustomFolder.Title.MAXIMAL_CHARACTERS_COUNT)]
public string Title { get; set; } = null!;

/* ━━━ Relatives ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
/* ─── Parent ───────────────────────────────────────────────────────────────────────────────────────────────────── */
/* [ Theory ] Although generally the explicit specifying of navigation property is optional, it is required for seeding. */
/* [ Theory ] `Guid.NewGuid()` return the string of 36 characters. See https://stackoverflow.com/a/4458925/4818123 */
[System.ComponentModel.DataAnnotations.MaxLength(36)]
public string? ParentID { get; set; }

public TaskCustomFolderModel? Parent { get; set; }

/* ─── Children ─────────────────────────────────────────────────────────────────────────────────────────────────── */
public List Children { get; set; } = [];

/* ━━━ Order Among Siblings ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
public uint OrderAmongSiblings { get; set; }

/* ━━━ Configuration ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
public class Configuration : Microsoft.EntityFrameworkCore.IEntityTypeConfiguration
{

private const string TABLE_NAME = "TasksCustomFolders";

public void Configure(
Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder builder)
{

builder.ToTable(Configuration.TABLE_NAME);

builder.
Property(taskCustomFolderModel => taskCustomFolderModel.Title).
IsRequired(TaskCustomFolder.Title.IS_REQUIRED);

builder.
Property(taskCustomFolderModel => taskCustomFolderModel.Parent).
IsRequired(TaskCustomFolder.Parent.IS_REQUIRED);

builder.
Property(taskCustomFolderModel => taskCustomFolderModel.ParentID).
IsRequired(TaskCustomFolder.Parent.IS_REQUIRED);

builder.
Property(taskCustomFolderModel => taskCustomFolderModel.Children).
IsRequired(TaskCustomFolder.Children.IS_REQUIRED);

builder.
Property(taskCustomFolderModel => taskCustomFolderModel.OrderAmongSiblings).
IsRequired(TaskCustomFolder.OrderAmongSiblings.IS_REQUIRED);

}

}

}
Ошибка при попытке заполнить базу данных с помощью base.Database.EnsureCreated();:

System.InvalidOperationException: 'Свойство 'List'
'TaskCustomFolderModel.Children' не может быть сопоставлено, поскольку
поставщик базы данных не поддерживает этот тип. Рассмотрите возможность преобразования
значения свойства в тип, поддерживаемый базой данных, с помощью преобразователя
значений. См. https://aka.ms/efcore-docs-value-converters для получения дополнительной
информации. Альтернативно исключите свойство из модели, используя
атрибут '[NotMapped]' или используя 'EntityTypeBuilder.Ignore' в
'OnModelCreating'.'

Согласно ошибке, поставщик базы данных что-то не поддерживает, однако приведенный ниже пример, который я использовал для справки и который также имеет отношения, работает нормально!

Код: Выделить всё

public class MenuItem
{
public int Id { get; set; }
public string? Title { get; set; }
public int? ParentId { get; set; }
public MenuItem? Parent { get; set; }
public List Children { get; set; } = new();
}

using Microsoft.EntityFrameworkCore;

public class ApplicationContext : DbContext
{
public DbSet MenuItems { get; set; } = null!;

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=helloapp.db");
}
}

using (ApplicationContext db = new ApplicationContext())
{

db.Database.EnsureDeleted();
db.Database.EnsureCreated();

MenuItem file = new MenuItem { Title = "File" };
MenuItem edit = new MenuItem { Title = "Edit" };
MenuItem open = new MenuItem { Title = "Open", Parent = file };
MenuItem save = new MenuItem { Title = "Save", Parent = file };

MenuItem copy = new MenuItem { Title = "Copy", Parent = edit };
MenuItem paste = new MenuItem { Title = "Paste", Parent = edit };

db.MenuItems.AddRange(file, edit, open, save, copy, paste);
db.SaveChanges();
}
using (ApplicationContext db = new ApplicationContext())
{

var menuItems = db.MenuItems.ToList();
Console.WriteLine("All Menu:");
foreach (MenuItem m in menuItems)
{
Console.WriteLine(m.Title);
}
Console.WriteLine();

var fileMenu = db.MenuItems.FirstOrDefault(m => m.Title == "File");
if(fileMenu != null)
{
Console.WriteLine(fileMenu.Title);
foreach(var m in fileMenu.Children)
{
Console.WriteLine($"---{m.Title}");
}
}
}
Так похоже проблема в чем-то другом, поэтому пока не скажу, какой провайдер БД использую.
Приложения
Классы контекста базы данных с исходным кодом

Код: Выделить всё

public class RemoteDatabaseContext : DatabaseContext
{

public RemoteDatabaseContext()
{

// base.Database.EnsureDeleted();
base.Database.EnsureCreated();

}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{

base.OnConfiguring(optionsBuilder);

optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Username=postgres;Password=pass1234");

}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{

modelBuilder.
Entity().
HasData(TaskCustomFolderModel.FromBusinessRulesEntities(SampleTasksCustomFoldersRepository.TaskCustomFolders));

}

}

public abstract class DatabaseContext : Microsoft.EntityFrameworkCore.DbContext
{

public DbSet TasksModels { get; internal set; } = null!;
public DbSet TaskCustomFoldersModels { get; internal set; } = null!;
public DbSet LocationModels { get; internal set; } = null!;

public DbSet PeopleModels { get; internal set; } = null!;

}
Почему вы устанавливаете IsRequired через Fluent API, а максимальное количество символов учитывается с помощью атрибутов?

Краткий ответ

Из-за чистой архитектуры, а также потому, что TaskCustomFolderModel и другие модели Entity Framework должны меняться из-за изменений в бизнес-правилах без возможности редактирования кода вручную.
Длинный ответ< /h3>
Согласно чистой архитектуре, бизнес-правила НЕ должны зависеть от каких-либо платформ, в то время как TaskCustomFolderModel зависит. Итак, помимо класса TaskCustomFolderModel есть еще один из бизнес-правил:

Код: Выделить всё

public class TaskCustomFolder
{

public required string ID { get; init; }

/* ━━━ Title ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
public required string title { get; set; }

public abstract record Title
{
public const bool IS_REQUIRED = true;
public const byte MINIMAL_CHARACTERS_COUNT = 1;
public const byte MAXIMAL_CHARACTERS_COUNT = Byte.MaxValue;
}

/* ━━━ Relatives ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
/* ─── Parent ───────────────────────────────────────────────────────────────────────────────────────────────────── */
public TaskCustomFolder? parent { get; set; }

public abstract record Parent
{
public const bool IS_REQUIRED = false;
}

/* ─── Children ─────────────────────────────────────────────────────────────────────────────────────────────────── */
public List children { get; set; } = [];

public abstract record Children
{
public const bool IS_REQUIRED = false;
}

/* ━━━ Order Among Siblings ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
public required uint orderAmongSiblings { get; set; }

public abstract record OrderAmongSiblings
{
public const bool IS_REQUIRED = true;
public const uint MINIMAL_VALUE = 1;
public const uint MAXIMAL_VALUE = UInt32.MaxValue;
}

/* ━━━ Path ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
public string path
{
get
{

TaskCustomFolder currentDepthLevel = this;
List pathSegments = [ currentDepthLevel.title ];

while (currentDepthLevel.parent is not null)
{
currentDepthLevel = currentDepthLevel.parent;
pathSegments.Add(currentDepthLevel.title);
}

return String.Join("/", pathSegments);

}
}

}
Если мы изменим MAXIMAL_CHARACTERS_COUNT какого-либо свойства, нет необходимости редактировать TaskCustomFolderModel, поскольку он ссылается на бизнес-правила через атрибут:

Код: Выделить всё

public class TaskCustomFolderModel
{

// ...   [System.ComponentModel.DataAnnotations.MaxLength(TaskCustomFolder.Title.MAXIMAL_CHARACTERS_COUNT)]
public string Title { get; set; } = null!;
}
Однако не существует атрибута Required, который принимает такой параметр, как TaskCustomFolder.Children.IS_REQUIRED. Так что это можно сделать только с помощью свободного API (или создания нового атрибута).


Подробнее здесь: https://stackoverflow.com/questions/791 ... ng-to-seed
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»