C# C中实体框架中的外键#
我已经使用java和hibernate很多年了,现在我开始使用C#,所以我想做一些与java差不多的事情 我喜欢注释,因为我喜欢将所有配置与实体保持在一起 我有两个班,城市和国家,城市有国家的外键C# C中实体框架中的外键#,c#,entity-framework,C#,Entity Framework,我已经使用java和hibernate很多年了,现在我开始使用C#,所以我想做一些与java差不多的事情 我喜欢注释,因为我喜欢将所有配置与实体保持在一起 我有两个班,城市和国家,城市有国家的外键 public class City { [Key] public long id { get; set; } public long countryId { get; set; } [ForeignKey("countryId")] public virtual
public class City {
[Key]
public long id { get; set; }
public long countryId { get; set; }
[ForeignKey("countryId")]
public virtual Country country { get; set; }
public string city { get; set; }
}
public class Country {
[Key]
public long id { get; set; }
public string country { get; set; }
public ICollection<City> Cities { get; set; }
}
另一个问题是,当我创建一个新城市时
public class CityService:ICityService {
public City getCity(string cityTxt, Country country) {
City city = null;
using (var ctx = new Context()) {
city = ctx.Cities.Where(it => it.city == cityTxt && it.country.id == country.id).FirstOrDefault();
if (city == null) {
city = ctx.Cities.Add(new City { city = cityTxt, countryId = country.id });
ctx.SaveChanges();
}
}
return city;
}
}
我设置了countryId
,保存新城市后,city.country
为空,是否有方法填充city.country
属性?如果我设置了countryId
和country
属性
city = ctx.Cities.Add(new City { city = cityTxt, countryId = country.id , country = country });
在ctx.SaveChanges()之后,将在数据库上创建该国家的重复实例
我仍在将我的java概念迁移到C#,因此非常感谢任何好的教程参考(如果使用Fluent API的instaid注释更好)
提前感谢。严格来说,不需要外键属性。不过有一个也不错(正如@GertArnold在评论中指出的,)
要加载country
属性,您需要实际加载它。这可以通过几种方式实现:
使用Include
,在查询时加载它:
myContext.Cities.Include(x => x.country).Where(...);
如果您的上下文启用了代理和延迟加载(默认情况下是这样),您可以访问属性进行读取(而上下文未被释放)以加载它:
using(var myContext = new Context())
{
var city = myContext.Cities.FirstOrDefault(x => x.city == "foo");
Console.WriteLine(city.country.country);
// if lazy loading is enabled, `city.country` will not be null after this
}
请注意,我正在使用
块在中访问city.country
。如果在上下文被释放后(在使用
块之外)尝试访问它,它将不起作用(因为它没有从何处检索数据的上下文和数据库连接)
随后加载引用:
var city = myContext.Cities.FirstOrDefault(x => x.city == "foo");
myContext.Entry(city).Reference(x => x.country).Load();
至于为什么在你的例子中会创建一个重复的实例。。。如果将导航属性(country
)设置为未附加到要保存的上下文的对象,则该对象将复制到数据库中(将其保存为新实体,并为其分配新密钥)。您可以:
保存前将您的国家/地区附加到上下文(此时不需要设置外键):
只需设置外键,并将国家
设为null
(这就是为什么外键属性很有用的原因):
提前从数据库(或缓存)加载国家/地区:
country = ctx.Countries.Find(country.id);
var city = new City { city = cityTxt, country = country };
city = ctx.Cities.Add(city);
实体框架6中的图形管理显然落后于Hibernate。它应该在EntityFrameworkCore中有一个更好的控件,但是尽管有“ReleaseCandidate”的名称,EFCore还没有准备好进行生产(老实说,考虑到他们在每一个RC版本上来回改变着一切,我想说,在问题解决之前,现在不值得在真正的应用程序上投资……不过这是一个挑战,你的里程可能会有所不同)
如果你习惯了冬眠的方式做事情,你可能想看看哪种方式更熟悉
PS:你的大小写很混乱,C#properties按照惯例使用TitleCase。当然你可以使用任何东西,但是如果你不习惯的话,你会发现大多数代码都很难读(我确实发现你的代码很难读,而且我也很难用你的大小写编写示例)你应该在C#中的属性中使用TitleCase。@Gusdor在C#中没有技术上的原因-但是,微软的指导方针很明确,应该这样做,每个人都这样做。我知道的每个公司都有与微软相近的指导方针,它们都符合CamelCase属性naming@Mafii我想你的意思是标题
(或Pascal
)大小写。虽然CamelCase
可能确实指的是这种大小写(通常称为UpperCamelCase
),但术语CamelCase
通常指的是“首字母小写,其余单词大写”(likeThis
):-)@Jcl哎呀,但我希望现在我所说的都清楚了meant@KasparsOzols这是你的观点,我同意。一些ppl可能不同意…@GertArnold好的和相关的答案,我将在我的答案上添加它作为一个链接。谢谢!谢谢@Jcl。虽然我觉得与Java Hibernate兼容,但我更喜欢尝试使用EntityFramework,也许它可以在未来。感谢您的TitleCase预约,我想以C#的方式编码。
ctx.Countries.Attach(country); // Attach the country to the context
var city = new City { city = cityTxt, country = country };
ctx.Cities.Add(city);
var city = new City { city = cityTxt, countryId = country.id /* don't set country */ };
ctx.Cities.Add(city);
country = ctx.Countries.Find(country.id);
var city = new City { city = cityTxt, country = country };
city = ctx.Cities.Add(city);