我的示例如下: 我有一个[Table1]与[Table2]有一对多的关系。
让它看起来像:
[Table1]:
[Id] int
[Table2]:
[Table1Id] int (foreign key to [Table1])
[UniqueColumnAtTable2ForGivenTable1Id] int
[Table2]确实具有[Table1]的外键,并且[Table2]中可能有多个与[Table1]相关的元素。
我知道如何通过代码定义[Table1]和[Table2]之间的映射,意思是:
public class Table1
{
public int Id { get; set; }
public virtual ICollection<Table2> Table2Objects { get; set; }
}
public class Table1_Mapping : EntityTypeConfiguration<Table1>
{
public class Table1()
{
this.HasKey(x => x.Id);
this.HasMany(x => x.Table2Objects).WithOptional().HasForeignKey(x => x.Table1);
}
}
但是有一种方法可以定义实体框架映射,在该映射中,我将指定一对多映射,但是只能映射到[Table2]中的一个特定行]?我确实在[Table2]上有 [UniqueColumnAtTable2ForGivenTable1Id] 列,该列对于给定的[Table1]始终是唯一的-因此,我知道运行类似这样的内容:
SELECT * FROM [Table2] WHERE [Table1Id] = 123 AND [UniqueColumnAtTable2ForGivenTable1Id] = 456
将始终只查询一行。
从C#代码中我需要的是这样的
public class Table1
{
public int Id { get; set; }
public virtual ICollection<Table2> Table2Objects { get; set; }
public virtual Table2 Table2Object456 { get; set; }
}
public class Table1_Mapping : EntityTypeConfiguration<Table1>
{
public class Table1()
{
this.HasKey(x => x.Id);
this.HasMany(x => x.Table2Objects).WithOptional().HasForeignKey(x => x.Table1);
this.MagicMethod(x => x.Table2Object456).WithOptional().HasForeignKey(x => x.Table1).OtherMagicMethodWhichAllowsToPutFilter(x => x.UniqueColumnAtTable2ForGivenTable1Id == 456);
}
}
当然我需要这个片段:
this.MagicMethod(x => x.Table2Object456).WithOptional().HasForeignKey(x => x.Table1).OtherMagicMethodWhichAllowsToPutFilter(x => x.UniqueColumnAtTable2ForGivenTable1Id == 456);
答案 0 :(得分:0)
只是了解您的实际需求。
我认为您想要这样的东西:
public class User {
public int Id { get; set; }
public int PrimaryAddressId { get; set;}
public virtual Address PrimaryAddress { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
EF应该自动建立PrimaryAddressId和导航属性之间的关系。
您真的不想要那种神奇的配置东西...除非您始终要与PrimaryAddress拥有相同的地址,否则您可以将其作为默认值来使用...但这似乎是一种代码味道可能不想这样做?
答案 1 :(得分:0)
我认为,好选项不是这样做的,而是在存储库中创建一个处理这种特殊情况的方法:
public class YourRepository
{
public Table2 Table2WithUniqueColumn456(Table1 table1)
{
using var context = new Table1Context();
return context.Entry(table1)
.Collection(t1 => t1.Table2Objects)
.Query()
.FirstOrDefault(t2 => t2.UniqueColumnAtTable2ForGivenTable1Id == 456);
}
}
现在,您每次需要获取一个等于456的Table2
时,都可以显式调用此方法。
如果您要好奇,那么坏的一种选择是利用继承:
public class Table1
{
public int Id { get; set; }
public virtual ICollection<Table2> Table2Objects { get; set; }
public virtual Table2WithUniqueColumn456 Table2Object456 { get; set; }
}
[Table("Table2")]
public class Table2
{
public int Id { get; set; }
public int Table1Id { get; set; }
public int UniqueColumnAtTable2ForGivenTable1Id { get; set; }
}
[Table("Table2")] // this will tell EF to use table-per-hierarchy
public class Table2WithUniqueColumn456 : Table2
{
}
public class Table1_Mapping : EntityTypeConfiguration<Table1>
{
public class Table1()
{
this.HasKey(x => x.Id);
this.HasMany(x => x.Table2Objects).WithOptional().HasForeignKey(x => x.Table1);
this.HasOne(x => x.Table2Object456).WithOptional().HasForeignKey(x => x.Table1);
}
}
如您所见:
UniqueColumnAtTable2ForGivenTable1Id
456的对象都被创建为Table2WithUniqueColumn456
UniqueColumnAtTable2ForGivenTable1Id
应该是不变的,否则可能带来更复杂的编辑逻辑Table2
也许,如果每个Table2
中没有那么多Table1
个对象,即使它不是那么有效,它也可能比继承更好。
public class Table1
{
public int Id { get; set; }
public virtual ICollection<Table2> Table2Objects { get; set; }
[NotMapped]
public virtual Table2WithUniqueColumn456 Table2Object456
{
get { return Table2Objects.FirstOrDefault(x => x.UniqueColumnAtTable2ForGivenTable1Id == 456; }
}
}