0

我有两个类一个用户和一个图像表:

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

这是错误的。我怎样才能正确地进行映射?

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

4

1 回答 1

0

查看此页面了解更多详情。

基本上一对一的关系是主实体的 PK 在从属实体中作为 PK 和 FK 传递的关系。据我在这里看到的,您需要将两个实体映射为彼此之间的可选实体,这在 EF 中实际上是不可能的,至少不是一到零或一。

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

用户作为主体:

//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 处理一对零或一关系的方式。

更新数据库后:

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

让我们尝试一下这种方法。让我知道这是否适合您。

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);
    }
}
于 2016-10-06T21:47:54.940 回答