首先是EF代码,如何在EF中将双向一对一或零关系映射?

时间:2016-10-06 17:56:54

标签: c# entity-framework ef-code-first ef-code-first-mapping

我有两个类User和Image表:

public class User
{
    public Guid? ImageId {get; set;}
    public Image Image {get; set;}
}

public class Image
{
    public Guid? UserId {get; set;}
    public User User {get; set;}
}

用户和图像都可以在没有其他实体的情况下独立存在,但如果它们确实存在关系,则用户只能与一个图像关联,而图像只能有用户,如果它们不为空。我该如何映射?目前我有:

public UserMapping()
    {            
        HasOptional(x => x.ProfileImage).WithOptionalPrincipal(x => 
        x.User).Map(x => x.MapKey("UserId"));
    }

在ImageMapping上没有任何内容,因为从其他答案中可以看出,它没有将关系映射两次,或者它变得怪异。但是,迁移文件最终会在Image表上生成一个额外的User_Id属性:

CreateTable(
            "dbo.Images",
            c => new
                {
                    Id = c.Guid(nullable: false),
                    UserId = c.Guid(),
                    User_Id = c.Guid(),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Users", t => t.User_Id)
            .Index(t => t.User_Id);

哪个错了。如何正确地进行映射?

编辑:我也发现了这个问题://stackoverflow.com/questions/21082085/entity-framework-optional-1-to-1-relation-on-both-ends并尝试了原始问题中显示的内容声称工作,但它没有,仍然创建User_Id。

1 个答案:

答案 0 :(得分:0)

查看this page了解更多详情。

基本上,一对一关系是主体实体的PK在依赖实体中作为PK和FK传递的关系。到目前为止,我可以在这里看到你需要将两个实体映射为彼此之间的可选项,而这在EF中是不可能的,至少不是One to Zero-Or-One。

我知道您希望双方都是可选的,但事实证明EF需要知道您的哪个实体是委托人。所以这是一种改变关系的方法。我建议你在关系中定义你的主体,另一个变成可选的。 E.g:

用户作为校长:

//Your entities
public class Image
{
    public Guid UserId { get; set; }

    public virtual User User { get; set; }
}

public class User
{
    public Guid UserId { get; set; }

    public virtual Image Image { get; set; }
}

//Mappings:
public class ImageMappingConfiguration : EntityTypeConfiguration<Image>
    {
        public ImageMappingConfiguration()
        {
            HasKey(x => x.UserId);
        }
    }

 public class UserMappingConfiguration : EntityTypeConfiguration<User>
    {
        public UserMappingConfiguration()
        {
            HasKey(x => x.UserId);

            HasOptional(x => x.Image)
                .WithRequired(x => x.User);
        }
    }

您可以在添加迁移后获得此内容:

public override void Up()
{
    CreateTable(
            "dbo.Images",
            c => new
            {
                UserId = c.Guid(nullable: false)
            })
        .PrimaryKey(t => t.UserId)
        .ForeignKey("dbo.Users", t => t.UserId)
        .Index(t => t.UserId);

    CreateTable(
            "dbo.Users",
            c => new
            {
                UserId = c.Guid(nullable: false)
            })
        .PrimaryKey(t => t.UserId);
}

查看用户传递PK和FK到Image的主键?这就是EF处理One to Zero-Or-One关系的方式。

After update-database:

  

UPDATE!具有唯一约束的两个一对多关系。

让我们尝试一下这种方法。如果这对您有用,请告诉我。

public sealed class Image
{
    public Image()
    {
        Users = new List<User>();
    }

    public Guid Id { get; set; }

    public Guid? UserId { get; set; }

    public List<User> Users { get; set; }

    public User User { get; set; }
}

public sealed class User
{
    public User()
    {
        Images = new List<Image>();
    }

    public Guid Id { get; set; }

    public Guid? ImageId { get; set; }

    public List<Image> Images { get; set; }

    public Image Image { get; set; }
}

//Mappings:
public class ImageMappingConfiguration : EntityTypeConfiguration<Image>
{
    public ImageMappingConfiguration()
    {
        HasKey(x => x.Id);

        Property(x => x.UserId)
            .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("IX_ImageMustBeUnique")
            {
                IsUnique = true
            }));


        HasMany(x => x.Users)
            .WithOptional(x => x.Image)
            .HasForeignKey(x => x.ImageId)
            .WillCascadeOnDelete(true);
    }
}

public class UserMappingConfiguration : EntityTypeConfiguration<User>
{
    public UserMappingConfiguration()
    {
        HasKey(x => x.Id);

        Property(x => x.ImageId)
            .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute("IX_UserMustBeUnique")
            {
                IsUnique = true
            }));

        HasMany(x => x.Images)
            .WithOptional(x => x.User)
            .HasForeignKey(x => x.UserId);
    }
}

<强>用法:

//test adding a user and an image.
var user = new User
{
    Id = Guid.NewGuid(),
};
var image = new Image
{
    Id = Guid.NewGuid(),
};

using (var ctx = new Context())
{
    ctx.Users.Add(user);
    ctx.Images.Add(image);
    ctx.SaveChanges();

    //associate them
    user.Images.Add(image);
    image.Users.Add(user);
    ctx.SaveChanges();

    //try to add a second image to the user
    var image2 = new Image
    {
        Id = Guid.NewGuid()
    };

    try
    {
        user.Images.Add(image2);
        ctx.SaveChanges();
    }
    catch (DbUpdateException ex)
    {
        Console.WriteLine(ex);
    }
}