Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C中实体框架中的外键#_C#_Entity Framework - Fatal编程技术网

C# C中实体框架中的外键#

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

我已经使用java和hibernate很多年了,现在我开始使用C#,所以我想做一些与java差不多的事情

我喜欢注释,因为我喜欢将所有配置与实体保持在一起

我有两个班,城市和国家,城市有国家的外键

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