实体框架 - 使用Fluent的两个没有导航属性的类之间的关系

时间:2013-12-12 12:12:16

标签: c# entity-framework

我有两个类(Person和Phone),我没有弄清楚如何在不创建导航属性的情况下在这些类之间创建关系。 有办法做到这一点吗?或者我必须创建一个导航属性?

在T-SQL中写作,我正在寻找这样的想法:

  

ALTER TABLE [dbo]。[PHONE] with NOCHECK         添加约束[RelationName1] FOREIGN KEY             ([PERSONID])             参考文献[dbo]。[PERSON]             ([PERSONID])

在下面的例子中,我不知道如何写这句话: modelBuilder.Entity<Person>().HasMany<Phone>().... ?????:

public class Person
{
    public int PersonId { get; set; }
    public string Name { get; set; }
}

public class Phone
{
    public int PhoneId { get; set; }
    public int PersonId { get; set; }
    public string PhoneNumber { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Person> People { get; set; }
    public DbSet<Phone> Phones { get; set; }
    public MyContext()
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Person>().HasMany<Phone>()...?????
    }
}

谢谢!

3 个答案:

答案 0 :(得分:1)

我认为,您至少需要在一个方向上使用导航属性。如果这导致序列化问题,您是否已调查添加属性以防止序列化?例如,在您的类上添加DataContractAttribute,并将DataMemberAttribute添加到您 想要序列化的所有属性中。

这会给你以下(我使用属性,但你可以使用流畅的配置):

[DataContract]
public class Person
{
    [Key]
    [DataMember]
    public int PersonId { get; set; }

    [DataMember]
    public string Name { get; set; }
}

[DataContract]
public class Phone
{
    [Key]
    [DataMember]
    public int PhoneId { get; set; }

    [DataMember]
    public int PersonId { get; set; }

    // No [DataMember] here.
    [ForeignKey("PersonId")]
    public Person Person { get; set; }

    [DataMember]
    public string PhoneNumber { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Person> People { get; set; }
    public DbSet<Phone> Phones { get; set; }

    public MyContext()
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // If I had a Phones collection on Person, I could use the other override
        // of WithMany.
        modelBuilder.Entity<Phone>().HasRequired(q => q.Person).WithMany();
    }
}

答案 1 :(得分:0)

单向(事实上,唯一指的是你的问题的第一个评论)我想通过覆盖初始化器并从初始化器的种子方法发送sql命令来实现目标。类似的东西:

public class CreateDatabaseIfNotExistsWithSeedData : CreateDatabaseIfNotExists<SomeContext> {

    protected override void Seed(SomeContext context) {
        base.Seed(context);

        context.Database.ExecuteSqlCommand("ALTER TABLE [dbo].[PHONE] WITH NOCHECK ADD CONSTRAINT [RelationName1] FOREIGN KEY ( [PERSONID] ) REFERENCES [dbo].[PERSON] ( [PERSONID] )");
    }
}

答案 2 :(得分:0)

根据您的评论,我可以建议

使用WebApi / JSON序列化这些类的问题

嗯,当您尝试序列化具有多对多(循环)关系的任何实体时,这是一个严重的问题。甚至忽略循环引用(由JSON.NET Serializer提供)也不起作用。您可以做的最好的事情是,您可以序列化您的确切实体,而不是序列化此实体的Linq .Select列表,即仅选择标量属性或从选择列表中忽略循环而不是必需的导航属性,然后将其序列化

我想避免EF在SaveChanges中插入子信息

你是什​​么意思?如果你的表中有一个外键,你必须有一个带有主键的主表,这个外键(PersonId)指向哪个主键?这意味着,您必须有一个表PersonMaster或类似的有或没有数据。实体框架对您来说很简单。如果您的意思是,您不想在PersonMaster中插入新数据,那么只需不要向Phone实体添加新的Person对象,找到Person(来自相同的上下文)然后添加它。 EntityFramework将只使用主键。 如果你试图说,你想在你的personId列中有一个值,这个值在其他任何地方都不存在,但仍然是外键,那你不可能知道吗?普通的SQL。