Entity Framework Code First Mapping Foreign Key с использованием Fluent API - PullRequest
8 голосов
/ 30 марта 2011

У меня есть ситуация, когда у пользователя может быть несколько адресов.Соответственно, у меня есть ICollection для моего пользовательского класса.Но я также хочу, чтобы пользователь мог выбрать адрес по умолчанию.Итак, я сделал следующее:

public class User 
{
    public int Id { get; set; }
    public int? DefaultAddressId { get; set; }
    [ForeignKey("DefaultAddressId")]
    public virtual Address DefaultAddress { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
    //properties were removed for purpose of this post
}

Я бы хотел удалить public virtual Address DefaultAddress { get; set; } в целом, оставить DefaultAddressId и сопоставить его с помощью Fluent API, потому что текущая настройка вызывает много проблем (в этом и других классах, где у меня есть аналогичные настройки).Так можно ли это сделать, используя свободный API?

ОБНОВЛЕНИЕ: В настоящее время класс адресов не имеет никакой ссылки на класс User, это однонаправленное отношение.Но да, адрес принадлежит только ОДНОМУ пользователю, это не много ко многим.Вот класс адресов:

public class Address
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Details { get; set; }
    public virtual Area Area { get; set; }
}

Ответы [ 4 ]

10 голосов
/ 30 марта 2011

Я бы лично переместил отношение внешнего ключа с User на Address и добавил бы свойство IsDefaultAddress к классу адресов.

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

    // This property marks the FK relation
    public virtual User User { get; set; }

    public string Name { get; set; }
    public string Details { get; set; }
    public virtual Area Area { get; set; }

    // This property signals whether this is the user's default address
    public bool IsDefaultAddress { get; set; }
}

EF будет знать, что ему нужно Foreign Key отношение между Address и User.

Это значительно упростит вашу модель. Это, конечно, если адрес может принадлежать только одному пользователю (как Слаума попросил в комментариях).

8 голосов
/ 31 марта 2011

Ваша оригинальная модель в вопросе должна работать. Вы можете проверить это довольно легко:

  • Создание нового консольного приложения (VS 2010)
  • Назовите его "EFTestApp"
  • Добавить ссылку на "EntityFramework.dll"
  • Удалите содержимое Program.cs и скопируйте следующий код в файл

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace EFTestApp
{
    public class User
    {
        public int Id { get; set; }
        public int? DefaultAddressId { get; set; }
        [ForeignKey("DefaultAddressId")]
        public virtual Address DefaultAddress { get; set; }
        public virtual ICollection<Address> Addresses { get; set; }
    }

    public class Address
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Context : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Address> Addresses { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new Context())
            {
                try
                {
                    User user = new User() { Addresses = new List<Address>() };

                    Address address1 = new Address() { Name = "Address1" };
                    Address address2 = new Address() { Name = "Address2" };

                    user.Addresses.Add(address1);
                    user.Addresses.Add(address2);

                    context.Users.Add(user);

                    context.SaveChanges();
                    // user has now 2 addresses in the DB and no DefaultAddress

                    user.DefaultAddress = address1;
                    context.SaveChanges();
                    // user has now address1 as DefaultAddress

                    user.DefaultAddress = address2;
                    context.SaveChanges();
                    // user has now address2 as DefaultAddress

                    user.DefaultAddress = null;
                    context.SaveChanges();
                    // user has now no DefaultAddress again
                }
                catch (Exception e)
                {
                    throw;
                }
            }
        }
    }
}

В SQL Server Express создается новая БД с именем «EFTestApp.Context». Вы можете установить контрольные точки для каждого SaveChanges выше, перешагнуть и наблюдать за изменениями в БД.

Если посмотреть на отношения в базе данных, то их два, а в таблице Addresses в БД есть столбец внешнего ключа User_Id.

Я думаю, вы также можете удалить public int? DefaultAddressId { get; set; } и [ForeignKey("DefaultAddressId")]. Он создает те же таблицы базы данных и отношения с необязательным параметром DefaultAddress.

Возможно, вы хотите, чтобы отношение Address -> User соответствовало требованиям (Адреса не могут жить одни в БД без Пользователя). Затем вы можете добавить это в класс Context:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>()
                .HasMany(u => u.Addresses)
                .WithRequired();
}

Это делает User_Id в таблице адресов недействительными и устанавливает каскадное удаление по умолчанию. Таким образом, когда пользователь удаляется, все его адреса также удаляются.

2 голосов
/ 30 марта 2011

DefaultAddressId не нуждается в каком-либо конкретном отображении, потому что это будет просто столбец в таблице User без какого-либо отношения (FK) к таблице Address.Не будет создано никакого отношения, потому что свойство навигации не существует ни с одной стороны.Также это должно быть отношение один к одному, которое не будет работать, потому что EF не поддерживает уникальные ключи.

Мне нравится решение, предоставляемое @Sergi Papaseit

0 голосов
/ 30 марта 2011

Вам не нужно отображать его, если вы удаляете свойство DefaultAddress.Вы можете просто иметь свойство там, и EF должен знать, как его отобразить, если DefaultAddressId находится в таблице User

...