我有这个现有的数据库模式,它意味着使用联合表自引用多对多关系。 位置表可能包含国家/地区,城市,地区,或地区等信息到Disciminator字段。表RelatedLocation保存自引用关系。
我的域模型如下,其中Location类是抽象类,每个继承类都包含相关的导航属性。
public abstract class Location
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Country : Location
{
public virtual ICollection<District> Districts { get; set; }
}
public class District : Location
{
public virtual ICollection<Country> Countries { get; set; }
public virtual ICollection<City> Cities { get; set; }
}
public class City : Location
{
public virtual ICollection<District> Districts { get; set; }
public virtual ICollection<Area> Areas { get; set; }
}
public class Area : Location
{
public virtual ICollection<City> Cities { get; set; }
}
On OnModelCreating我使用以下内容来映射每个继承类的多对多关系
modelBuilder.Entity<Country>()
.HasMany(c => c.Districts)
.WithMany(d => d.Countries)
.Map(t => t.ToTable("RelatedLocations").MapLeftKey("ParentId").MapRightKey("RelatedId"));
modelBuilder.Entity<City>()
.HasMany(c => c.Districts)
.WithMany(d => d.Cities)
.Map(t => t.ToTable("RelatedLocations").MapLeftKey("ParentId").MapRightKey("RelatedId"));
在创建模型时,我接收并执行“每个EntitySet必须引用一个独特的模式和表”,即EF抱怨将不同关系映射到同一个表“ RelatedLocaions ”不止一次
我不知道EF4.1不支持这种方式的映射,或者我用错误的方法映射它!
答案 0 :(得分:4)
我怀疑你正在尝试的映射是否可行。我会尝试类似的东西:
public abstract class Location
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Location> ParentLocations { get; set; }
public virtual ICollection<Location> RelatedLocations { get; set; }
}
public class Country : Location
{
// readonly = not mapped
public IEnumerable<District> Districts
{
get { return RelatedLocations.OfType<District>(); }
}
}
public class District : Location
{
public IEnumerable<Country> Countries
{
get { return ParentLocations.OfType<Country>(); }
}
public IEnumerable<City> Cities
{
get { return RelatedLocations.OfType<City>(); }
}
}
// same approch for the other collections
然后这个映射:
modelBuilder.Entity<Location>()
.HasMany(l => l.ParentLocations)
.WithMany(l => l.RelatedLocations)
.Map(t => t.ToTable("RelatedLocations")
.MapLeftKey("ParentId")
.MapRightKey("RelatedId"));
多对多映射始终位于ParentLocations
和RelatedLocations
之间,但这些集合根据您使用的具体类型填充了派生类的不同实例。只读集合只是在内存中执行类型转换的帮助程序(基于ParentLocations
和RelatedLocations
实体的延迟加载{/ 1}}。
修改强>
也许不是使用{em>过滤来自源集合中Location
类型的所有对象的.OfType<T>()
,而是T
更可能尝试投射所有源集合中的对象键入.Cast<T>()
并在无法进行转换时抛出异常。它应该基本上导致相同的结果,因为基类中的T
应始终仅由相同的派生类型填充。例如:ICollection<Location>
应仅包含Country.RelatedLocations
类型的实体。但也许在这种情况下异常是好的,因为它表明出现了错误,而不是默默地忽略集合中另一种类型的实体(District
会这样做。)
修改2
我想强调OfType
集合是 helpers ,它允许您检索具有派生类型的实体。集合只执行类型转换,仅此而已。它们与映射到数据库无关,EF甚至没有“看到”它们存在。您可以删除它们,并且EF模型和数据库表列,关系和引用约束中不会发生任何变化。
您将如何在此模型中添加和检索实体?例子:
添加一个新的IEnumerable
,其中包含Country
个实体列表:
District
再次检索此实体:
var country = new Country() { RelatedLocations = new List<Location>() };
country.Name = "Palau";
// ParentLocations stays empty because Country has no parents
var district1 = new District { Name = "District1" };
var district2 = new District { Name = "District2" };
country.RelatedLocations.Add(district1); // because District is a Location
country.RelatedLocations.Add(district2);
context.Locations.Add(country); // because Country is a Location
context.SaveChanges();
检索区:
var country = context.Locations.OfType<Country>()
.SingleOrDefault(c => c.Name == "Palau");
// now get the districts, RelatedLocations is lazily loaded
var districts = country.RelatedLocations.Cast<District>();
// What type is districts? It's an IEnumerable<District>.
// So we can also use a helper property:
// var districts = country.Districts;
编辑3
您可以创建一个延迟加载代理,而不是使用var district = context.Locations.OfType<District>()
.SingleOrDefault(d => d.Name == "District1");
var countries = district.ParentLocations.Cast<Country>();
// or with the helper: var countries = district.Countries;
// countries collection contains Palau, because of many-to-many relation
创建Country
。然后,您无需初始化new
集合。我想知道这对于派生类型是如何工作的,但我发现有一个带有通用参数的RelatedLocations
重载用于此目的:
Create