Entitätstypen mit KonstruktorenEntity types with constructors

Hinweis

Dieses Feature ist neu in EF Core 2.1.This feature is new in EF Core 2.1.

Ab EF Core 2.1, ist es jetzt möglich, definieren Sie einen Konstruktor mit Parametern und dass EF Core, die dieser Konstruktor aufgerufen, wenn Sie eine Instanz der Entität zu erstellen.Starting with EF Core 2.1, it is now possible to define a constructor with parameters and have EF Core call this constructor when creating an instance of the entity. Parameter des Konstruktors an zugeordneten Eigenschaften gebunden werden können, oder auf verschiedene Arten von Diensten zu ermöglichen wie Verhalten lazy Loading.The constructor parameters can be bound to mapped properties, or to various kinds of services to facilitate behaviors like lazy-loading.

Hinweis

Ab EF Core 2.1 ist alle Konstruktor-Bindung gemäß der Konvention.As of EF Core 2.1, all constructor binding is by convention. Konfiguration von bestimmten Konstruktoren verwenden, ist für eine künftige Version geplant.Configuration of specific constructors to use is planned for a future release.

Binden an die zugeordnete EigenschaftenBinding to mapped properties

Betrachten Sie ein typisches Modell für die Blog-Beitrag:Consider a typical Blog/Post model:

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; }
}

Wenn Instanzen dieser Typen von EF Core erstellt wird, wie z. B. für die Ergebnisse einer Abfrage, sie rufen Sie zuerst dem parameterlosen Standardkonstruktor und klicken Sie dann auf den Wert jeder Eigenschaft festgelegt, aus der Datenbank.When EF Core creates instances of these types, such as for the results of a query, it will first call the default parameterless constructor and then set each property to the value from the database. Jedoch wenn EF Core mit einen parametrisierten Konstruktor gefunden Parameternamen und -Typen, die übereinstimmen zugeordnet Eigenschaften, und es den parametrisierten Konstruktor mit den Werten für diese Eigenschaften aufzurufen, und jede Eigenschaft nicht explizit festgelegt.However, if EF Core finds a parameterized constructor with parameter names and types that match those of mapped properties, then it will instead call the parameterized constructor with values for those properties and will not set each property explicitly. Zum Beispiel:For example:

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; }
}

Einige Punkte zu beachten:Some things to note:

  • Nicht alle Eigenschaften müssen Konstruktorparameter.Not all properties need to have constructor parameters. Beispielsweise wird die Post.Content-Eigenschaft von einzelnen Konstruktorparameter nicht festgelegt, damit EF Core er nach dem Aufruf des Konstruktors, auf die übliche Weise festgelegt werden.For example, the Post.Content property is not set by any constructor parameter, so EF Core will set it after calling the constructor in the normal way.
  • Der Parametertypen und muss mit dem Unterschied, dass Eigenschaften Pascal-Schreibweise verwendet werden, während die Parameter in Kamel-Schreibweise werden Eigenschaftstypen und -Namen übereinstimmen.The parameter types and names must match property types and names, except that properties can be Pascal-cased while the parameters are camel-cased.
  • EF Core kann nicht festgelegt Navigationseigenschaften (z. B. Blog oder Ihre Beiträge, die oben genannten) über einen Konstruktor.EF Core cannot set navigation properties (such as Blog or Posts above) using a constructor.
  • Der Konstruktor kann als öffentlich, privat, oder eine beliebige andere zugriffsmöglichkeiten aufweisen.The constructor can be public, private, or have any other accessibility. Lazy Loading-Proxys erfordern jedoch, dass der Konstruktor über die erbende Klasse für den Anwendungsproxy zugänglich ist.However, lazy-loading proxies require that the constructor is accessible from the inheriting proxy class. In der Regel bedeutet dies entweder öffentliche oder geschützte erleichtert.Usually this means making it either public or protected.

Schreibgeschützte EigenschaftenRead-only properties

Nach Eigenschaften über den Konstruktor festgelegt werden können einige Schreibschutz sinnvoll.Once properties are being set via the constructor it can make sense to make some of them read-only. EF Core unterstützt, aber es gibt einige Dinge achten:EF Core supports this, but there are some things to look out for:

  • Eigenschaften ohne Setter werden gemäß der Konvention nicht zugeordnet.Properties without setters are not mapped by convention. (Dies ist zum Zuordnen von Eigenschaften, die nicht, wie z. B. berechnete Eigenschaften zugeordnet werden soll.)(Doing so tends to map properties that should not be mapped, such as computed properties.)
  • Die Verwendung von automatisch generierten Schlüsselwerte erfordert eine wichtige Eigenschaft, die Lese-/ Schreibzugriff, da der Schlüsselwert durch den Generator für Zugriffsschlüssel festgelegt werden, wenn neue Entitäten einfügen muss.Using automatically generated key values requires a key property that is read-write, since the key value needs to be set by the key generator when inserting new entities.

Eine einfache Möglichkeit, diese Probleme vermeiden werden private Setter verwendet.An easy way to avoid these things is to use private setters. Zum Beispiel:For example:

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; }
}

EF Core sieht eine Eigenschaft mit einem privaten Setter als Lese-/ Schreibzugriff, d. h., die alle Eigenschaften wie zuvor zugeordnet sind, und der Schlüssel kann immer noch vom Speicher generierte werden.EF Core sees a property with a private setter as read-write, which means that all properties are mapped as before and the key can still be store-generated.

Eine Alternative zur Verwendung von private Setter, werden Eigenschaften wirklich schreibgeschützt machen, und fügen weitere explizite Zuordnung in "onmodelcreating" ab.An alternative to using private setters is to make properties really read-only and add more explicit mapping in OnModelCreating. Einige Eigenschaften können auch vollständig entfernt und durch nur Felder ersetzt werden.Likewise, some properties can be removed completely and replaced with only fields. Betrachten Sie beispielsweise die folgenden Entitätstypen:For example, consider these entity types:

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; }
}

Und diese Konfiguration in "onmodelcreating":And this configuration in 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);
        });
}

Beachten Sie Folgendes:Things to note:

  • Der Schlüssel "Property" ist jetzt ein Feld.The key "property" is now a field. Es ist keiner readonly Feld, damit vom Speicher generierte Schlüssel verwendet werden können.It is not a readonly field so that store-generated keys can be used.
  • Die anderen Eigenschaften sind schreibgeschützte Eigenschaften, die nur im Konstruktor festgelegt.The other properties are read-only properties set only in the constructor.
  • Wenn der primäre Schlüsselwert ist immer nur, indem EF festlegen oder aus der Datenbank gelesen, dann besteht keine Notwendigkeit zum Einschließen in den Konstruktor.If the primary key value is only ever set by EF or read from the database, then there is no need to include it in the constructor. Dies bewirkt, dass den Schlüssel "Property" als ein einfaches Feld und macht deutlich, dass sie nicht explizit festgelegt werden soll, wenn neue Blogs und Beiträgen zu erstellen.This leaves the key "property" as a simple field and makes it clear that it should not be set explicitly when creating new blogs or posts.

Hinweis

Dieser Code führt zu compilerwarnung "169" gibt an, dass das Feld nie verwendet wird.This code will result in compiler warning '169' indicating that the field is never used. Dies kann ignoriert werden, da in der Praxis EF Core das Feld in einer Weise extralinguistic verwendet wird.This can be ignored since in reality EF Core is using the field in an extralinguistic manner.

Einfügen von DienstenInjecting services

EF Core kann auch "Dienste" in einen Entitätstyp-Konstruktor einfügen.EF Core can also inject "services" into an entity type's constructor. Beispielsweise kann die folgenden eingefügt werden:For example, the following can be injected:

  • DbContext – die aktuelle Context-Instanz, die auch als Ihr abgeleiteter Typ von "DbContext" eingegeben werden kannDbContext - the current context instance, which can also be typed as your derived DbContext type
  • ILazyLoader -der-Lazy Load-Dienst – finden Sie unter der lazy Loading-Dokumentation Weitere DetailsILazyLoader - the lazy-loading service--see the lazy-loading documentation for more details
  • Action<object, string> -einen lazy Loading-Delegaten – finden Sie unter der lazy Loading Dokumentation Weitere DetailsAction<object, string> - a lazy-loading delegate--see the lazy-loading documentation for more details
  • IEntityType -die EF Core-Metadaten, die dieser Entitätstyp zugeordnetIEntityType - the EF Core metadata associated with this entity type

Hinweis

Ab EF Core 2.1 können nur Dienste, die von EF Core bekannte eingefügt werden.As of EF Core 2.1, only services known by EF Core can be injected. Unterstützung für das Einschleusen von Anwendungsdiensten ist für eine spätere Version in Betracht gezogen.Support for injecting application services is being considered for a future release.

Beispielsweise kann ein eingefügter "DbContext" verwendet werden, selektiv Zugriff auf die Datenbank Informationen zu verknüpften Entitäten zu erhalten, ohne Sie zu laden, alle.For example, an injected DbContext can be used to selectively access the database to obtain information about related entities without loading them all. Im folgenden Beispiel wird dies verwendet, um die Anzahl an Beiträgen, die in einem Blog zu erhalten, ohne Sie zu laden die Beiträge:In the example below this is used to obtain the number of posts in a blog without loading the posts:

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; }
}

Einige Punkte zu beachten Sie dazu zu erhalten:A few things to notice about this:

  • Der Konstruktor ist privat, da immer nur durch von EF Core Aufruf ist und eine andere öffentlicher Konstruktor zur allgemeinen Verwendung vorhanden ist.The constructor is private, since it is only ever called by EF Core, and there is another public constructor for general use.
  • Der Code, der mit dem eingefügten Dienst (d. h. der Kontext) ist dafür defensive wird null um Fälle zu behandeln, in denen EF Core ist nicht das Erstellen die Instanz.The code using the injected service (that is, the context) is defensive against it being null to handle cases where EF Core is not creating the instance.
  • Da Service in einer Lese-/Schreibzugriff-Eigenschaft gespeichert wird werden sie zurückgesetzt werden, wenn die Entität an eine neue Kontextinstanz angefügt ist.Because service is stored in a read/write property it will be reset when the entity is attached to a new context instance.

Warnung

Einfügen von "DbContext" wie folgt, wird häufig als Antimuster betrachtet, da die Entitätstypen direkt mit EF Core verkoppelt.Injecting the DbContext like this is often considered an anti-pattern since it couples your entity types directly to EF Core. Vor der Verwendung von Dienst-Injection wie folgt alle Optionen sorgfältig prüfen.Carefully consider all options before using service injection like this.