Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Można zdefiniować konstruktor z parametrami i pozwolić EF Core wywołać ten konstruktor podczas tworzenia wystąpienia jednostki. Parametry konstruktora można powiązać z zamapowanych właściwości lub różnego rodzaju usług, aby ułatwić takie zachowania jak leniwe ładowanie.
Uwaga / Notatka
Obecnie wszystkie powiązania konstruktora odbywają się zgodnie z konwencją. Zaplanowano konfigurację określonych konstruktorów do użycia w przyszłej wersji.
Wiązanie z mapowanymi właściwościami
Rozważ typowy model bloga/wpisu:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public ICollection<Post> Posts { get; } = new List<Post>();
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime PostedOn { get; set; }
public Blog Blog { get; set; }
}
Gdy program EF Core tworzy wystąpienia tych typów, na przykład dla wyników zapytania, najpierw wywoła domyślny konstruktor bez parametrów, a następnie ustawi każdą właściwość na wartość z bazy danych. Jeśli jednak program EF Core znajdzie sparametryzowany konstruktor z nazwami parametrów i typami, które pasują do właściwości mapowanych, zamiast tego wywoła sparametryzowany konstruktor z wartościami dla tych właściwości i nie ustawi jawnie każdej właściwości. Przykład:
public class Blog
{
public Blog(int id, string name, string author)
{
Id = id;
Name = name;
Author = author;
}
public int Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public ICollection<Post> Posts { get; } = new List<Post>();
}
public class Post
{
public Post(int id, string title, DateTime postedOn)
{
Id = id;
Title = title;
PostedOn = postedOn;
}
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime PostedOn { get; set; }
public Blog Blog { get; set; }
}
Niektóre kwestie do zapamiętania:
- Nie wszystkie właściwości muszą mieć parametry konstruktora. Na przykład właściwość Post.Content nie jest ustawiana przez żaden parametr konstruktora, dlatego program EF Core ustawi ją po wywołaniu konstruktora w normalny sposób.
- Typy parametrów i nazwy muszą być zgodne z typami i nazwami właściwości, z tą różnicą, że właściwości mogą być zapisywane w stylu Pascal, podczas gdy nazwy parametrów są zapisywane w stylu camel.
- Program EF Core nie może ustawić właściwości nawigacji (takich jak blog lub wpisy powyżej) przy użyciu konstruktora.
- Konstruktor może być publiczny, prywatny lub ma inne ułatwienia dostępu. Jednak serwery proxy z leniwym ładowaniem wymagają, aby konstruktor był dostępny z klasy proxy dziedziczącej. Zazwyczaj oznacza to upublicznienie lub ochronę.
Właściwości tylko do odczytu
Gdy właściwości są ustawiane za pomocą konstruktora, można ustawić niektóre z nich jako tylko do odczytu. EF Core obsługuje to, ale są pewne kwestie, na które należy zwrócić uwagę:
- Właściwości bez setterów nie są mapowane zgodnie z konwencją. (W ten sposób ma tendencję do mapowania właściwości, które nie powinny być mapowane, na przykład właściwości obliczone).
- Użycie automatycznie wygenerowanych wartości klucza wymaga właściwości klucza, która jest odczyt-zapis, ponieważ wartość klucza musi być ustawiana przez generator kluczy podczas wstawiania nowych jednostek.
Łatwym sposobem uniknięcia tych problemów jest użycie prywatnych setterów. Przykład:
public class Blog
{
public Blog(int id, string name, string author)
{
Id = id;
Name = name;
Author = author;
}
public int Id { get; private set; }
public string Name { get; private set; }
public string Author { get; private set; }
public ICollection<Post> Posts { get; } = new List<Post>();
}
public class Post
{
public Post(int id, string title, DateTime postedOn)
{
Id = id;
Title = title;
PostedOn = postedOn;
}
public int Id { get; private set; }
public string Title { get; private set; }
public string Content { get; set; }
public DateTime PostedOn { get; private set; }
public Blog Blog { get; set; }
}
Program EF Core widzi właściwość z prywatnym ustawiaczem jako odczyt-zapis, co oznacza, że wszystkie właściwości są mapowane tak jak poprzednio, a klucz nadal może być generowany przez magazyn.
Alternatywą dla używania setterów prywatnych jest utworzenie właściwości rzeczywiście tylko do odczytu i dodanie bardziej jawnego mapowania w elemencie OnModelCreating. Podobnie niektóre właściwości można całkowicie usunąć i zastąpić tylko polami. Rozważmy na przykład następujące typy jednostek:
public class Blog
{
private int _id;
public Blog(string name, string author)
{
Name = name;
Author = author;
}
public string Name { get; }
public string Author { get; }
public ICollection<Post> Posts { get; } = new List<Post>();
}
public class Post
{
private int _id;
public Post(string title, DateTime postedOn)
{
Title = title;
PostedOn = postedOn;
}
public string Title { get; }
public string Content { get; set; }
public DateTime PostedOn { get; }
public Blog Blog { get; set; }
}
A ta konfiguracja w elemencie OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>(
b =>
{
b.HasKey("_id");
b.Property(e => e.Author);
b.Property(e => e.Name);
});
modelBuilder.Entity<Post>(
b =>
{
b.HasKey("_id");
b.Property(e => e.Title);
b.Property(e => e.PostedOn);
});
}
Kwestie do zanotowania:
- Klucz "property" jest teraz polem. To nie jest pole
readonly, aby można było używać kluczy generowanych przez magazyn. - Pozostałe właściwości są właściwościami tylko do odczytu ustawionymi tylko w konstruktorze.
- Jeśli wartość klucza podstawowego jest ustawiana tylko przez program EF lub odczyt z bazy danych, nie ma potrzeby dołączania jej do konstruktora. Pozostawia to atrybut "właściwość" jako pole podstawowe i jasno wskazuje, że nie powinno być ustawiane bezpośrednio podczas tworzenia nowych blogów lub wpisów.
Uwaga / Notatka
Ten kod spowoduje wyświetlenie ostrzeżenia kompilatora "169" wskazującego, że pole nigdy nie jest używane. Można to zignorować, ponieważ w rzeczywistości program EF Core używa pola w sposób ekstralingwistyczny.
Wstrzykiwanie usług
Program EF Core może również wstrzyknąć "usługi" do konstruktora typu jednostki. Na przykład można wstrzyknąć następujące elementy:
-
DbContext— bieżące wystąpienie kontekstu, które można również określić jako Twój pochodny typ DbContext -
ILazyLoader- lazy-loading service – zobacz dokumentację lazy-loading, aby uzyskać więcej szczegółów -
Action<object, string>- delegat do ładowania leniwego -- szczegóły znajdziesz w dokumentacji ładowania leniwego -
IEntityType— metadane platformy EF Core skojarzone z tym typem jednostki
Uwaga / Notatka
Obecnie można wstrzykiwać tylko usługi znane przez EF Core. Obsługa integracji usług aplikacji jest rozważana w kontekście przyszłej wersji.
Na przykład wstrzyknięta metoda DbContext może służyć do selektywnego uzyskiwania dostępu do bazy danych w celu uzyskania informacji o powiązanych jednostkach bez ładowania ich wszystkich. W poniższym przykładzie użyto metody uzyskiwania liczby wpisów w blogu bez ładowania wpisów:
public class Blog
{
public Blog()
{
}
private Blog(BloggingContext context)
{
Context = context;
}
private BloggingContext Context { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public ICollection<Post> Posts { get; set; }
public int PostsCount
=> Posts?.Count
?? Context?.Set<Post>().Count(p => Id == EF.Property<int?>(p, "BlogId"))
?? 0;
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime PostedOn { get; set; }
public Blog Blog { get; set; }
}
Kilka rzeczy, na które warto zwrócić uwagę:
- Konstruktor jest prywatny, ponieważ jest wywoływany tylko przez program EF Core i istnieje inny publiczny konstruktor do użytku ogólnego.
- Kod, który korzysta z wstrzykniętej usługi (czyli kontekstu), jest odporny na sytuacje, gdy jest ona ustawiona na null, aby obsługiwać przypadki, w których EF Core nie tworzy wystąpienia.
- Ponieważ usługa jest przechowywana we właściwości odczytu/zapisu, zostanie zresetowana po dołączeniu obiektu do nowego wystąpienia kontekstu.
Ostrzeżenie
Wstrzykiwanie elementu DbContext w ten sposób jest często uznawane za antywzór, ponieważ łączy typy jednostek bezpośrednio z platformą EF Core. Przed użyciem iniekcji usługi należy dokładnie rozważyć wszystkie opcje.