实体框架代码首先使用Fluent API映射外键

Kas*_*sem 8 entity-framework fluent-interface ef-code-first entity-framework-4.1

我的情况是用户可以拥有多个地址.因此,我的用户类上有一个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
}
Run Code Online (Sandbox Code Playgroud)

我想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; }
}
Run Code Online (Sandbox Code Playgroud)

Ser*_*eit 10

我个人移动外键关系,从UserAddress,并添加一个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; }
}
Run Code Online (Sandbox Code Playgroud)

EF将知道它需要和Foreign Key之间的关系.AddressUser

这将大大简化您的模型.也就是说,如果一个地址只能属于一个用户(如评论中的Slauma所述).

  • 老实说,我会选择问题中的解决方案.我不知道为什么它不应该工作(我刚刚测试过它很好.它创建了2个关系.)在你的解决方案中,必须确保在业务逻辑中"IsDefaultAddress"的设置不超过一个用户的地址.如果更改DefaultAddress,则必须搜索旧地址并重置旧标志.在我看来,问题中的解决方案更好地表达了模型的"自然"关系,并且不需要担心重复的默认标志. (5认同)

Sla*_*uma 8

您问题中的原始模型应该有效.你可以很容易地测试它:

  • 创建新的控制台应用程序(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;
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在SQL Server Express中,它创建一个名为"EFTestApp.Context"的新数据库.您可以在上面的每个SaveChanges上设置断点,跳过并观察数据库中的更改.

如果查看数据库中的关系,则有两个,并且AddressesDB 中的表是外键列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();
}
Run Code Online (Sandbox Code Playgroud)

它使User_IdAddresses表中的不可为空,并默认设置级联删除.因此,当用户被删除时,其所有地址也会被删除.