Подтвердить что ты не робот

Как объявить отношения один к одному с использованием Entity Framework 4 Code First (POCO)

Как объявить отношения один к одному с использованием Entity Framework 4 Code First (POCO)?

Я нашел этот вопрос (взаимно-однозначные отношения в Entity Framework 4), но статья о том, что ссылки на ответы не была полезной (есть одна строка код, который является отношением 1-1, но не упоминает, как его определить).

4b9b3361

Ответ 1

Вы просто ищете что-то вроде этого?

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public Profile Profile { get; set; }
    public int ProfileId { get; set; }
}

public class Profile
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PostalCode { get; set; }
    // etc...
}

public class UserMapping : EntityConfiguration<User>
{
    public UserMapping()
    {
        this.HasKey(u => u.Id);
        this.Property(u => u.Username).HasMaxLength(32);

        // User has ONE profile.
        this.HasRequired(u => u.Profile);
    }
}

public class ProfileMapping : EntityConfiguration<Profile>
{
    public ProfileMapping()
    {
        this.HasKey(p => p.Id);
        this.Property(p => p.FirstName).HasMaxLength(32);
        this.Property(p => p.LastName).HasMaxLength(32);
        this.Property(p => p.PostalCode).HasMaxLength(6);
    }
}

EDIT: Да, у меня не было VS передо мной, но вам нужно добавить следующую строку в UserMapping вместо текущей HasRequired, а также добавить ProfileId свойство (вместо Profile_Id, которое вы добавили):

this.HasRequired(u => u.Profile).HasConstraint((u, p) => u.ProfileId == p.Id);

В настоящее время я не думаю об этом, но я уверен, что это изменится, так как мы только в CTP4. Было бы неплохо, если бы я мог сказать:

this.HasRequired(u => u.Profile).WithSingle().Map(
    new StoreForeignKeyName("ProfileId"));

Таким образом, мне не нужно было бы включать свойство ProfileId. Может быть, есть способ обойти это сейчас, и мне еще рано утром подумать:).

Также не забудьте вызвать .Include("Profile"), если вы хотите включить "навигационное свойство".

Ответ 2

Три метода:

A) Объявите оба класса с свойствами навигации друг к другу. Отметьте одну из таблиц (зависимую таблицу) с атрибутом ForeignKey на ее Первичном ключе. EF отображает от 1 до 1:

public class AppUser
{
    public int Id { get; set; }

    public string Username { get; set; }

    public OpenIdInfo OpenIdInfo { get; set; }
}

​public class OpenIdInfo
{
    [ForeignKey("AppUser")]
    public int Id { get; set; }

    public string OpenId { get; set; }

    public AppUser AppUser { get; set; }
}

http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx

Я не использовал virtual, и вы тоже не должны. *

B) Объявите иерархию наследования с явно указанными именами таблиц, в результате получим Table-Per-Type и общий первичный ключ.

using System.ComponentModel.DataAnnotations;

[Table("AppUser")]
public class AppUser
{
    public int Id { get; set; }

    public string Username { get; set; }

    public OpenIdInfo OpenIdInfo { get; set; }
}

[Table("AdminUser")]      
public class AdminUser : AppUser
{
    public bool SuperAdmin { get; set; }
}

Вы получите 2 таблицы: один для AppUser, один для AdminUser. AdminUser - 1:1 с AppUser и является зависимым - это означает, что вы можете удалить AdminUser, но если вы удалите AppUser, когда AdminUser все еще указывает на него, вы получите ошибку нарушения ограничений.

C) В EF есть два метода полуфабрикатов:

Entity-Splitting, где у вас есть один класс, но он хранится в первичной таблице и 1 или более один к одному связанных таблиц.

Table-Splitting, где дерево объектов сливается в одну таблицу. Например, класс с свойством Address имел бы столбцы для объекта Address, такие как Address_City, сглаженные в одну таблицу.

* Вы можете включить виртуальные объекты в любое свойство или коллекции EF если вы хотите ленить их загрузить. Это может привести к бесконечным циклам или загрузке всей БД, если вы передадите объект с ленивыми загружаемыми свойствами, например, в конвертер MVC JSON или что-нибудь еще, проходящее по иерархии объектов. Lazy-Loading всегда выполняется синхронно, блокируя поток и без какого-либо уведомления. Подводя итог, список способов замораживания вашего кода, приложения или сервера с ним длинный. Избегайте использования виртуальных классов EF. Да, в Интернете есть много примеров кода, которые его используют. Нет, вы все равно не должны его использовать.

Ответ 3

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }

    public virtual Profile Profile { get; set; }
}

public class Profile
{
    public int Id { get; set; }

    public int UserID { get; set; }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PostalCode { get; set; }
}

Добавьте виртуальный профиль и UserID, и я думаю, что вы должны туда добраться.

Ответ 4

Возьмем пример следующих объектов Student и StudentAddress.
Настроить отношения "один-на-один-один" с помощью DataAnnotations:

public class Student
{
    public Student() { }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public virtual StudentAddress Address { get; set; }

}

public class StudentAddress 
{
    [ForeignKey("Student")]
    public int StudentAddressId { get; set; }

    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public int Zipcode { get; set; }
    public string State { get; set; }
    public string Country { get; set; }

    public virtual Student Student { get; set; }
}

Когда объект StudentAddress не соответствует соглашениям:

Если, например, объект StudentAddress не соответствует соглашению для ПК, то есть другому имени для свойства Id, вам также необходимо настроить его для ПК. Рассмотрим следующий объект StudentAddress, который имеет имя свойства StudentId вместо StudentAddressId.

public class Student
{
    public Student() { }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public virtual StudentAddress Address { get; set; }

}

public class StudentAddress 
{
    [Key, ForeignKey("Student")]
    public int StudentId { get; set; }

    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public int Zipcode { get; set; }
    public string State { get; set; }
    public string Country { get; set; }

    public virtual Student Student { get; set; }
}

В приведенном выше примере нам нужно настроить свойство StudentId как Key, а также ForeignKey. Это приведет к тому, что свойство StudentId в объекте StudentAddress будет равно PK и FK.

Настройка отношений "один-к-одному" с использованием Fluent API:
Когда Student и StudentAddress следуют соглашениям: Субъекты Student и StudentAddress следуют стандарту Code-first для PrimaryKey. Поэтому нам не нужно настраивать их для определения своих PrimaryKeys. Нам нужно только настроить объект StudentAddress, где StudentAddressId должен быть ForeignKey.

В следующем примере устанавливаются отношения "один-к-ноль" или "один" между Student и StudentAddress с использованием Fluent API.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{

    // Configure Student & StudentAddress entity
    modelBuilder.Entity<Student>()
                .HasOptional(s => s.Address) // Mark Address property optional in Student entity
                .WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student

}

В приведенном выше примере объект Student настроен с использованием метода HasOptional(), который указывает, что свойство навигации StudentAddress в объекте Student является необязательным (не требуется при сохранении объекта Student). Затем метод WithRequired() настраивает объект StudentAddress и создает свойство Student Navigation для StudentAddress по мере необходимости (требуется при сохранении сущности StudentAddress. Он генерирует исключение, когда объект StudentAddress сохраняет без свойства навигации Student). Это также сделает StudentAddressId как ForeignKey.

Таким образом, вы можете настроить отношения "один-на-один-один" между двумя объектами, где объект-ученик можно сохранить без привязки к нему объекта StudentAddress, но объект "StudentAddress" не может быть сохранен без присоединения объекта объекта "Студент". Это требует одного конца.

Когда объект StudentAddress не соответствует соглашениям:
Теперь давайте возьмем пример объекта StudentAddress, где он не соответствует принципу первичного ключа, т.е. Имеет другое имя свойства Id, чем Id. Рассмотрим следующие объекты Student и StudentAddress.

public class Student
{
    public Student() { }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public virtual StudentAddress Address { get; set; }

}

public class StudentAddress 
{
    public int StudentId { get; set; }

    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public int Zipcode { get; set; }
    public string State { get; set; }
    public string Country { get; set; }

    public virtual Student Student { get; set; }
}

Итак, теперь нам нужно настроить свойство StudentId для StudentAddress для PrimaryKey StudentAddress, а также ForeignKey, как показано ниже.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure StudentId as PK for StudentAddress
    modelBuilder.Entity<StudentAddress>()
        .HasKey(e => e.StudentId);

    // Configure StudentId as FK for StudentAddress
    modelBuilder.Entity<Student>()
                .HasOptional(s => s.Address) 
                .WithRequired(ad => ad.Student); 

}

Настройка отношений "один-к-одному" с использованием Fluent API:
Мы можем настроить отношения "один-к-одному" между объектами, использующими Fluent API, где требуются оба конца, что означает, что объект объекта Student должен включать объект объекта StudentAddress, а объект StudentAddress должен включать объект объекта "Студент", чтобы сохранить его.

Примечание. Связь "один-к-одному" технически невозможна в MS SQL Server. Он всегда будет от одного до нуля или один. EF формирует отношения "один-к-одному" на объектах, не входящих в БД.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure StudentId as PK for StudentAddress
    modelBuilder.Entity<StudentAddress>()
        .HasKey(e => e.StudentId);

    // Configure StudentId as FK for StudentAddress
    modelBuilder.Entity<Student>()
                .HasRequired(s => s.Address) 
                .WithRequiredPrincipal(ad => ad.Student); 

}

В приведенном выше примере modelBuilder.Entity(). HasRequired (s = > s.Address) делает свойство Address для StudentAddress обязательным..WithRequiredPrincipal(ad = > ad.Student) делает свойство Student объекта StudentAddress по мере необходимости. Таким образом, он настраивает оба конца. Итак, теперь, когда вы пытаетесь сохранить объект Student без адреса или объекта StudentAddress без Student, он выдает исключение.

Ссылка: http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx