關聯性Relationships

關聯性定義的兩個實體如何與彼此相關。A relationship defines how two entities relate to each other. 在關聯式資料庫中,這是外部索引鍵條件約束所表示。In a relational database, this is represented by a foreign key constraint.

注意

大部分的這篇文章中的範例會使用一對多關聯性,來示範概念。Most of the samples in this article use a one-to-many relationship to demonstrate concepts. 如需一對一和多對多關聯性的範例,請參閱其他關聯性模式發行項的最後一節。For examples of one-to-one and many-to-many relationships see the Other Relationship Patterns section at the end of the article.

詞彙定義Definition of Terms

有許多的詞彙用於描述關聯性There are a number of terms used to describe relationships

  • 相依的實體: 這是包含外部索引鍵屬性的實體。Dependent entity: This is the entity that contains the foreign key property(s). 有時稱為 'child' 的關聯性。Sometimes referred to as the 'child' of the relationship.

  • 主要實體: 這是包含的主要/替代索引鍵屬性的實體。Principal entity: This is the entity that contains the primary/alternate key property(s). 有時稱為 'parent' 的關聯性。Sometimes referred to as the 'parent' of the relationship.

  • 外部索引鍵: 中用來儲存與相關實體的主要索引鍵內容值的相依實體屬性。Foreign key: The property(s) in the dependent entity that is used to store the values of the principal key property that the entity is related to.

  • 主體的金鑰: 屬性可唯一識別與主要實體。Principal key: The property(s) that uniquely identifies the principal entity. 這可能是主索引鍵或替代索引鍵。This may be the primary key or an alternate key.

  • 導覽屬性: 包含相關的公司實體參考的主體和 (或) 相依實體上定義的屬性。Navigation property: A property defined on the principal and/or dependent entity that contains a reference(s) to the related entity(s).

    • 集合導覽屬性: 導覽屬性,其中包含許多相關實體的參考。Collection navigation property: A navigation property that contains references to many related entities.

    • 參考導覽屬性: 保留單一相關實體的參考導覽屬性。Reference navigation property: A navigation property that holds a reference to a single related entity.

    • 反向導覽屬性: 時討論特定的導覽屬性時,此一詞是指關聯性另一端的導覽屬性。Inverse navigation property: When discussing a particular navigation property, this term refers to the navigation property on the other end of the relationship.

下列程式碼清單會顯示一對多關聯性之間BlogPostThe following code listing shows a one-to-many relationship between Blog and Post

  • Post為相依實體Post is the dependent entity

  • Blog是主要實體Blog is the principal entity

  • Post.BlogId外部索引鍵Post.BlogId is the foreign key

  • Blog.BlogId是 (在此情況下它是主索引鍵,而不是替代索引鍵) 的主要索引鍵Blog.BlogId is the principal key (in this case it is a primary key rather than an alternate key)

  • Post.Blog是參考導覽屬性Post.Blog is a reference navigation property

  • Blog.Posts是集合導覽屬性Blog.Posts is a collection navigation property

  • Post.Blog是反向導覽屬性的Blog.Posts(反之亦然)Post.Blog is the inverse navigation property of Blog.Posts (and vice versa)

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

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

慣例Conventions

依照慣例,在類型上探索到的導覽屬性時將會建立關聯性。By convention, a relationship will be created when there is a navigation property discovered on a type. 屬性會被視為導覽屬性,如果它所指向的類型可以對應為純量型別目前的資料庫提供者。A property is considered a navigation property if the type it points to can not be mapped as a scalar type by the current database provider.

注意

關聯性探索到的慣例會永遠以目標主要實體的主索引鍵。Relationships that are discovered by convention will always target the primary key of the principal entity. 若要以其他的索引鍵為目標,額外的設定必須使用 Fluent API 執行。To target an alternate key, additional configuration must be performed using the Fluent API.

完整定義的關聯性Fully Defined Relationships

關聯性的最常見的模式是已定義這兩個端點的關聯性和相依的實體類別中定義的外部索引鍵屬性的導覽屬性。The most common pattern for relationships is to have navigation properties defined on both ends of the relationship and a foreign key property defined in the dependent entity class.

  • 如果找不到導覽屬性配對是兩個類型之間,它們將會設定為相同關聯性的反向導覽屬性。If a pair of navigation properties is found between two types, then they will be configured as inverse navigation properties of the same relationship.

  • 如果相依的實體包含一個名為屬性<primary key property name><navigation property name><primary key property name>,或<principal entity name><primary key property name>接著,它會設定為外部索引鍵。If the dependent entity contains a property named <primary key property name>, <navigation property name><primary key property name>, or <principal entity name><primary key property name> then it will be configured as the foreign key.

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

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

警告

如果有多個定義兩個類型之間的導覽屬性 (也就是多個相異點彼此的巡覽組) 慣例再建立任何關聯性,您必須手動將其設定為識別方式導覽屬性配對。If there are multiple navigation properties defined between two types (i.e. more than one distinct pair of navigations that point to each other), then no relationships will be created by convention and you will need to manually configure them to identify how the navigation properties pair up.

沒有外部索引鍵屬性No Foreign Key Property

雖然建議有相依的實體類別中定義的外部索引鍵屬性,並不需要。While it is recommended to have a foreign key property defined in the dependent entity class, it is not required. 如果不找到任何外部索引鍵屬性,將介紹陰影的外部索引鍵屬性具有名稱<navigation property name><principal key property name>(請參閱遮蔽屬性如需詳細資訊)。If no foreign key property is found, a shadow foreign key property will be introduced with the name <navigation property name><principal key property name> (see Shadow Properties for more information).

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

    public Blog Blog { get; set; }
}

單一瀏覽屬性Single Navigation Property

包括一個導覽屬性 (沒有反向導覽,以及任何外部索引鍵屬性),即已足夠有依慣例定義關聯性。Including just one navigation property (no inverse navigation, and no foreign key property) is enough to have a relationship defined by convention. 您也可以讓單一導覽屬性和外部索引鍵屬性。You can also have a single navigation property and a foreign key property.

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

串聯刪除Cascade Delete

依照慣例,cascade delete 將會設定為Cascade必要的關聯性和ClientSetNull選擇性的關聯性。By convention, cascade delete will be set to Cascade for required relationships and ClientSetNull for optional relationships. Cascade表示相依實體也會一併刪除。Cascade means dependent entities are also deleted. ClientSetNull方法不會載入記憶體的相依實體將會保留不變且必須以手動方式刪除,或更新為指向有效的主要實體。ClientSetNull means that dependent entities that are not loaded into memory will remain unchanged and must be manually deleted, or updated to point to a valid principal entity. 載入到記憶體的實體,EF 核心會嘗試將外部索引鍵屬性設定為 null。For entities that are loaded into memory, EF Core will attempt to set the foreign key properties to null.

請參閱必要和選擇性的關聯性必要和選擇性的關聯性之間的差異 > 一節。See the Required and Optional Relationships section for the difference between required and optional relationships.

請參閱Cascade Delete的更多詳細的不同刪除行為和使用慣例的預設值。See Cascade Delete for more details about the different delete behaviors and the defaults used by convention.

資料註釋Data Annotations

有兩個可用來設定關聯性的資料註解[ForeignKey][InverseProperty]There are two data annotations that can be used to configure relationships, [ForeignKey] and [InverseProperty].

[ForeignKey][ForeignKey]

若要設定哪些屬性應作為外部索引鍵屬性指定的關聯性,您可以使用資料註解。You can use the Data Annotations to configure which property should be used as the foreign key property for a given relationship. 這通常是依照慣例探索不到外部索引鍵屬性時。This is typically done when the foreign key property is not discovered by convention.

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

    public int BlogForeignKey { get; set; }

    [ForeignKey("BlogForeignKey")]
    public Blog Blog { get; set; }
}

提示

[ForeignKey]註解可以放在關聯性中的任一個導覽屬性。The [ForeignKey] annotation can be placed on either navigation property in the relationship. 不需要相依的實體類別中的導覽屬性上移。It does not need to go on the navigation property in the dependent entity class.

[InverseProperty][InverseProperty]

您可以使用資料註解來設定相依及主體實體上的導覽屬性如何配對。You can use the Data Annotations to configure how navigation properties on the dependent and principal entities pair up. 這通常是一對以上兩個實體類型之間的導覽屬性時。This is typically done when there is more than one pair of navigation properties between two entity types.

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int AuthorUserId { get; set; }
    public User Author { get; set; }

    public int ContributorUserId { get; set; }
    public User Contributor { get; set; }
}

public class User
{
    public string UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    [InverseProperty("Author")]
    public List<Post> AuthoredPosts { get; set; }

    [InverseProperty("Contributor")]
    public List<Post> ContributedToPosts { get; set; }
}

關於 fluent 應用程式開發介面Fluent API

若要設定關聯性 Fluent API 中,您必須啟動用來識別組成關聯性的導覽屬性。To configure a relationship in the Fluent API, you start by identifying the navigation properties that make up the relationship. HasOneHasMany識別您在開始設定的實體類型上的導覽屬性。HasOne or HasMany identifies the navigation property on the entity type you are beginning the configuration on. 您接著鏈結呼叫WithOneWithMany來識別反向導覽。You then chain a call to WithOne or WithMany to identify the inverse navigation. HasOne/WithOne用於參考導覽屬性和HasMany / WithMany用於集合導覽屬性。HasOne/WithOne are used for reference navigation properties and HasMany/WithMany are used for collection navigation properties.

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts);
    }
}

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

    public Blog Blog { get; set; }
}

單一瀏覽屬性Single Navigation Property

如果您只需要一個導覽屬性,則有無參數多載的WithOneWithManyIf you only have one navigation property then there are parameterless overloads of WithOne and WithMany. 這表示有在概念上是參考或關聯性另一端的集合,但沒有包含在實體類別中的導覽屬性。This indicates that there is conceptually a reference or collection on the other end of the relationship, but there is no navigation property included in the entity class.

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasMany(b => b.Posts)
            .WithOne();
    }
}

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

外部索引鍵Foreign Key

您可以使用 fluent 應用程式開發的應用程式開發介面來設定哪些屬性應為外部索引鍵屬性用於指定關聯性。You can use the Fluent API to configure which property should be used as the foreign key property for a given relationship.

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .HasForeignKey(p => p.BlogForeignKey);
    }
}

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

    public int BlogForeignKey { get; set; }
    public Blog Blog { get; set; }
}

下列程式碼清單示範如何設定複合外部索引鍵。The following code listing shows how to configure a composite foreign key.

class MyContext : DbContext
{
    public DbSet<Car> Cars { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Car>()
            .HasKey(c => new { c.State, c.LicensePlate });

        modelBuilder.Entity<RecordOfSale>()
            .HasOne(s => s.Car)
            .WithMany(c => c.SaleHistory)
            .HasForeignKey(s => new { s.CarState, s.CarLicensePlate });
    }
}

public class Car
{
    public string State { get; set; }
    public string LicensePlate { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }

    public List<RecordOfSale> SaleHistory { get; set; }
}

public class RecordOfSale
{
    public int RecordOfSaleId { get; set; }
    public DateTime DateSold { get; set; }
    public decimal Price { get; set; }

    public string CarState { get; set; }
    public string CarLicensePlate { get; set; }
    public Car Car { get; set; }
}

您可以使用的字串多載HasForeignKey(...)陰影屬性設定為外部索引鍵 (請參閱遮蔽屬性如需詳細資訊)。You can use the string overload of HasForeignKey(...) to configure a shadow property as a foreign key (see Shadow Properties for more information). 我們建議您明確陰影屬性加入至模型之前使用的外部索引鍵為 (如下所示)。We recommend explicitly adding the shadow property to the model before using it as a foreign key (as shown below).

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Add the shadow property to the model
        modelBuilder.Entity<Post>()
            .Property<int>("BlogForeignKey");

        // Use the shadow property as a foreign key
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .HasForeignKey("BlogForeignKey");
    }
}

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

    public Blog Blog { get; set; }
}

主體金鑰Principal Key

如果您想要參考的屬性以外的主索引鍵的外部索引鍵,您可以使用 fluent 應用程式開發的應用程式開發介面來設定關聯性的主要索引鍵內容。If you want the foreign key to reference a property other than the primary key, you can use the Fluent API to configure the principal key property for the relationship. 您將設定為主要索引鍵會自動屬性是做為替代索引鍵的安裝程式 (請參閱替代索引鍵如需詳細資訊)。The property that you configure as the principal key will automatically be setup as an alternate key (see Alternate Keys for more information).

class MyContext : DbContext
{
    public DbSet<Car> Cars { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<RecordOfSale>()
            .HasOne(s => s.Car)
            .WithMany(c => c.SaleHistory)
            .HasForeignKey(s => s.CarLicensePlate)
            .HasPrincipalKey(c => c.LicensePlate);
    }
}

public class Car
{
    public int CarId { get; set; }
    public string LicensePlate { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }

    public List<RecordOfSale> SaleHistory { get; set; }
}

public class RecordOfSale
{
    public int RecordOfSaleId { get; set; }
    public DateTime DateSold { get; set; }
    public decimal Price { get; set; }

    public string CarLicensePlate { get; set; }
    public Car Car { get; set; }
}

下列程式碼清單示範如何設定複合主體索引鍵。The following code listing shows how to configure a composite principal key.

class MyContext : DbContext
{
    public DbSet<Car> Cars { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<RecordOfSale>()
            .HasOne(s => s.Car)
            .WithMany(c => c.SaleHistory)
            .HasForeignKey(s => new { s.CarState, s.CarLicensePlate })
            .HasPrincipalKey(c => new { c.State, c.LicensePlate });
    }
}

public class Car
{
    public int CarId { get; set; }
    public string State { get; set; }
    public string LicensePlate { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }

    public List<RecordOfSale> SaleHistory { get; set; }
}

public class RecordOfSale
{
    public int RecordOfSaleId { get; set; }
    public DateTime DateSold { get; set; }
    public decimal Price { get; set; }

    public string CarState { get; set; }
    public string CarLicensePlate { get; set; }
    public Car Car { get; set; }
}

警告

您可以在其中指定主體的索引鍵屬性的順序必須符合指定的外部索引鍵的順序。The order in which you specify principal key properties must match the order in which they are specified for the foreign key.

必要和選擇性的關聯性Required and Optional Relationships

您可以設定關聯性是否必要或選擇性使用 fluent 應用程式開發的應用程式開發介面。You can use the Fluent API to configure whether the relationship is required or optional. 最終這會控制外部索引鍵屬性是必要或選擇性。Ultimately this controls whether the foreign key property is required or optional. 當您使用陰影狀態外部索引鍵,這是最有用。This is most useful when you are using a shadow state foreign key. 如果您有實體類別中的外部索引鍵屬性,則關聯性的 requiredness 取決於外部索引鍵屬性是必要或選擇性 (請參閱必要與選用屬性如需詳細資訊資訊)。If you have a foreign key property in your entity class then the requiredness of the relationship is determined based on whether the foreign key property is required or optional (see Required and Optional properties for more information).

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .IsRequired();
    }
}

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

    public Blog Blog { get; set; }
}

串聯刪除Cascade Delete

您可以使用 Fluent API 來明確設定指定的關聯性的串聯刪除行為。You can use the Fluent API to configure the cascade delete behavior for a given relationship explicitly.

請參閱Cascade Delete上儲存的資料區段的每個選項的詳細討論。See Cascade Delete on the Saving Data section for a detailed discussion of each option.

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

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

    public int? BlogId { get; set; }
    public Blog Blog { get; set; }
}

其他關聯性模式Other Relationship Patterns

一對一One-to-one

一對一關聯性兩端具有參考導覽屬性。One to one relationships have a reference navigation property on both sides. 它們遵循相同的慣例,作為一對多關聯性,但外部索引鍵屬性,以確保只有一個相關與每個主體上引進唯一索引。They follow the same conventions as one-to-many relationships, but a unique index is introduced on the foreign key property to ensure only one dependent is related to each principal.

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public BlogImage BlogImage { get; set; }
}

public class BlogImage
{
    public int BlogImageId { get; set; }
    public byte[] Image { get; set; }
    public string Caption { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

注意

EF 會選擇其中一個要能夠偵測到外部索引鍵屬性為基礎的相依實體。EF will choose one of the entities to be the dependent based on its ability to detect a foreign key property. 如果不正確的實體會被選為相依項,您可以使用 fluent 應用程式開發的應用程式開發介面來修正這個問題。If the wrong entity is chosen as the dependent, you can use the Fluent API to correct this.

設定關聯性 fluent 應用程式開發的應用程式開發介面,當您使用HasOneWithOne方法。When configuring the relationship with the Fluent API, you use the HasOne and WithOne methods.

設定您需要指定的相依實體類型的外部索引鍵時發現提供給泛型參數HasForeignKey下面的清單中。When configuring the foreign key you need to specify the dependent entity type - notice the generic parameter provided to HasForeignKey in the listing below. 在一對多關聯性會清除使用參考瀏覽該實體是相依,而與集合是主體。In a one-to-many relationship it is clear that the entity with the reference navigation is the dependent and the one with the collection is the principal. 但這不是一對一的關聯性-因此,不需要明確定義它。But this is not so in a one-to-one relationship - hence the need to explicitly define it.

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<BlogImage> BlogImages { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasOne(p => p.BlogImage)
            .WithOne(i => i.Blog)
            .HasForeignKey<BlogImage>(b => b.BlogForeignKey);
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public BlogImage BlogImage { get; set; }
}

public class BlogImage
{
    public int BlogImageId { get; set; }
    public byte[] Image { get; set; }
    public string Caption { get; set; }

    public int BlogForeignKey { get; set; }
    public Blog Blog { get; set; }
}

多對多Many-to-many

尚不支援多對多關聯性沒有實體類別,以代表聯結的資料表。Many-to-many relationships without an entity class to represent the join table are not yet supported. 不過,您可以藉由聯結資料表和對應兩個不同的一對多關聯性的實體類別表示多對多關聯性。However, you can represent a many-to-many relationship by including an entity class for the join table and mapping two separate one-to-many relationships.

class MyContext : DbContext
{
    public DbSet<Post> Posts { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<PostTag>()
            .HasKey(t => new { t.PostId, t.TagId });

        modelBuilder.Entity<PostTag>()
            .HasOne(pt => pt.Post)
            .WithMany(p => p.PostTags)
            .HasForeignKey(pt => pt.PostId);

        modelBuilder.Entity<PostTag>()
            .HasOne(pt => pt.Tag)
            .WithMany(t => t.PostTags)
            .HasForeignKey(pt => pt.TagId);
    }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public List<PostTag> PostTags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

    public List<PostTag> PostTags { get; set; }
}

public class PostTag
{
    public int PostId { get; set; }
    public Post Post { get; set; }

    public string TagId { get; set; }
    public Tag Tag { get; set; }
}