Свойства теней и индексатора
Теневые свойства — это свойства, которые не определены в классе сущностей .NET, но определены для этого типа сущности в модели EF Core. Значение и состояние этих свойств поддерживаются исключительно в средстве отслеживания изменений. Теневые свойства полезны, если в базе данных есть данные, которые не должны предоставляться для сопоставленных типов сущностей.
Свойства индексатора — это свойства типа сущности, которые поддерживаются индексатором в классе сущностей .NET. Доступ к им можно получить с помощью индексатора в экземплярах класса .NET. Он также позволяет добавлять дополнительные свойства к типу сущности без изменения класса CLR.
Свойства тени внешнего ключа
Теневые свойства чаще всего используются для свойств внешнего ключа, где они добавляются в модель по соглашению, когда не было найдено или явно настроено никакое свойство внешнего ключа. Связь представлена свойствами навигации, но в базе данных она обеспечивается ограничением внешнего ключа, а значение столбца внешнего ключа хранится в соответствующем свойстве тени.
Свойство будет называться <navigation property name><principal key property name>
(для именования используется навигация по зависимой сущности, которая указывает на основную сущность). Если имя свойства ключа субъекта начинается с имени свойства навигации, то это будет просто <principal key property name>
. Если для зависимой сущности нет свойства навигации, вместо нее используется имя типа субъекта.
Например, следующий листинг кода приведет к BlogId
тому, что свойство shadow будет представлено в сущности Post
:
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
// Since there is no CLR property which holds the foreign
// key for this relationship, a shadow property is created.
public Blog Blog { get; set; }
}
Настройка свойств тени
Для настройки свойств тени можно использовать API Fluent . После вызова строковой перегрузки Property<TProperty>(String)можно связать любой из вызовов конфигурации для других свойств. В следующем примере, так как Blog
не имеет свойства CLR с именем LastUpdated
, создается свойство shadow:
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property<DateTime>("LastUpdated");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Если имя, предоставленное методу Property
, совпадает с именем существующего свойства (теневое свойство или свойство, определенное в классе сущностей), код настраивает это существующее свойство, а не вводит новое свойство тени.
Доступ к свойствам тени
Значения свойств shadow можно получить и изменить с помощью ChangeTracker
API:
context.Entry(myBlog).Property("LastUpdated").CurrentValue = DateTime.Now;
На теневые свойства можно ссылаться в запросах LINQ с помощью EF.Property
статического метода:
var blogs = context.Blogs
.OrderBy(b => EF.Property<DateTime>(b, "LastUpdated"));
Доступ к теневым свойствам после запроса без отслеживания невозможен, так как возвращенные сущности не отслеживаются с помощью средства отслеживания изменений.
Настройка свойств индексатора
Для настройки свойств индексатора можно использовать API Fluent. После вызова метода IndexerProperty
можно связать любой из вызовов конфигурации для других свойств. В следующем примере определен индексатор, Blog
который будет использоваться для создания свойства индексатора.
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().IndexerProperty<DateTime>("LastUpdated");
}
}
public class Blog
{
private readonly Dictionary<string, object> _data = new Dictionary<string, object>();
public int BlogId { get; set; }
public object this[string key]
{
get => _data[key];
set => _data[key] = value;
}
}
Если имя, предоставленное методу IndexerProperty
, совпадает с именем существующего свойства индексатора, код настроит это существующее свойство. Если тип сущности имеет свойство, которое поддерживается свойством класса сущностей, возникает исключение, так как доступ к свойствам индексатора должен осуществляться только через индексатор.
На свойства индексатора можно ссылаться в запросах LINQ с помощью EF.Property
статического метода, как показано выше, или с помощью свойства индексатора CLR.
Типы сущностей контейнера свойств
Типы сущностей, содержащие только свойства индексатора, называются типами сущностей контейнера свойств. Эти типы сущностей не имеют свойств теней, и ВМЕСТО этого EF создает свойства индексатора. В настоящее время поддерживается только Dictionary<string, object>
в качестве типа сущности контейнера свойств. Он должен быть настроен как тип сущности общего типа с уникальным именем, а соответствующее DbSet
свойство должно быть реализовано с помощью Set
вызова .
internal class MyContext : DbContext
{
public DbSet<Dictionary<string, object>> Blogs => Set<Dictionary<string, object>>("Blog");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.SharedTypeEntity<Dictionary<string, object>>(
"Blog", bb =>
{
bb.Property<int>("BlogId");
bb.Property<string>("Url");
bb.Property<DateTime>("LastUpdated");
});
}
}
Типы сущностей контейнера свойств можно использовать везде, где используется обычный тип сущности, в том числе как собственный тип сущности. Однако они имеют некоторые ограничения: