实体框架代码优先中的关系 [英] Relationships in Entity Framework Code First

查看:41
本文介绍了实体框架代码优先中的关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

昨天我在 Management Studio 中创建了数据库,现在我想使用 EF Code First 在程序中创建它.

yesterday I created database in Management Studio and now I want to create it in program using EF Code First.

这里是我的数据库的链接:http://s11.postimg.org/6sv6cucgj/1462037_646961388683482.jpg

Here is link to my database: http://s11.postimg.org/6sv6cucgj/1462037_646961388683482_1557326399_n.jpg

我做了什么:

public class GameModel
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }
    public DateTime CreationTime { get; set; }
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }
    public string TotalTime { get; set; }
    public DateTime RouteStartTime { get; set; }
    public DateTime RouteEndTime { get; set; }
    public int MaxPlayersPerTeam { get; set; }

    public int CityId { get; set; }
    public int CreatorId { get; set; }
    [InverseProperty("Id")]
    [ForeignKey("CreatorId")]
    //public int TeamId { get; set; }
    //[ForeignKey("TeamId")]

    public virtual UserModel Creator { get; set; }
    public virtual CityModel City { get; set; }
    //public virtual TeamModel WinnerTeam { get; set; }


}
public class RegionModel
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public virtual ICollection<CityModel> Cities { get; set; }
}
public class CityModel
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public int RegionId { get; set; }

    public virtual RegionModel Region { get; set; }

    public virtual ICollection<UserModel> Users { get; set; }
    public virtual ICollection<GameModel> Games { get; set; }
}
public class UserModel
{
    [Key]
    public int Id { get; set; }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Login { get; set; }
    public string Password { get; set; }
    public string Email { get; set; }
    public DateTime RegistrationDate { get; set; }
    public string FacebookId { get; set; }

    public int CityId { get; set; }

    public virtual CityModel City { get; set; }

    public virtual IEnumerable<GameModel> Games { get; set; }
}

现在我想创建 4 个表,但我遇到了一些问题......我想在 GameModel 中创建 CreatorId,但它不起作用......当我写 UserId 而不是 CreatorId 时它正在工作(没有 [InverseProperty("Id")] 和 [ForeignKey("CreatorId")]).

For now I wanted to create 4 tables but I have some problems... I want to make CreatorId in GameModel, but it doesn't work... When i wrote UserId instead of CreatorId it was working ( without [InverseProperty("Id")] and [ForeignKey("CreatorId")]).

这是我得到的:

无法将视图属性Id"配置为导航属性.该属性必须是有效的实体类型,并且该属性应该具有非抽象的 getter 和 setter.对于集合属性,该类型必须实现 ICollection,其中 T 是有效的实体类型.或其主人未找到或没有视图引擎支持搜索的位置.

The view 'The property 'Id' cannot be configured as a navigation property. The property must be a valid entity type and the property should have a non-abstract getter and setter. For collection properties the type must implement ICollection where T is a valid entity type.' or its master was not found or no view engine supports the searched locations.

我是这样改的:

    public int CityId { get; set; }
    public int CreatorId { get; set; }

    [ForeignKey("CityId")]
    public virtual CityModel City { get; set; }
    [ForeignKey("CreatorId")]
    public virtual UserModel Creator { get; set; }

还有另一个问题.

表UserModels"上的引入 FOREIGN KEY 约束"FK_dbo.UserModels_dbo.CityModels_CityId 视图可能会导致循环或多个级联路径.指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束.无法创建约束.见以前的错误.或其主人未找到或没有视图引擎支持搜索的位置.

The view 'Introducing FOREIGN KEY constraint 'FK_dbo.UserModels_dbo.CityModels_CityId' on table 'UserModels' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors.' or its master was not found or no view engine supports the searched locations.

我不知道如何解决.

推荐答案

InversePropertyAttribute 指定该关系应使用哪个导航属性.

The InversePropertyAttribute specifies, which navigation property should be used for that relation.

导航属性必须是实体类型(例如在模型中声明的类型,GameModel)或实现 ICollection 的某种类型,其中 T 必须是实体类型.UserModel.Id 是一个 int,显然不满足那个条件.

A navigation property must be of an entity type (the types declared in your model, GameModel for example) or some type implementing ICollection<T>, where T has to be an entity type. UserModel.Id is an int, which clearly doesn't satisfy that condition.

因此,如果您将类型更改为 ICollection,则 GameModel.Creator 的逆属性可能是 UserModel.Games,或者必须不指定.如果您不指定逆属性,EF 将尝试自行解决所有问题(在这种情况下,它会正确地将 GameModel.Creator 识别为导航属性,但 UserModel.Games 很可能会抛出异常,因为它既不是实体类型,也没有实现 ICollectionT 是实体类型,也不是从数据库的角度来看,它是一种原始类型).然而,EF 的 work-everything-out-by-itself-magic 并不能很好地处理相同实体类型之间的多个关系,这就是需要 InversePropertyAttribute 的时候.

So, the inverse property of GameModel.Creator could be UserModel.Games if you changed the type to ICollection<GameModel>, or had to be left unspecified. If you don't specify an inverse property, EF will try to work everything out on its own (in this case it would properly recognize GameModel.Creator as a navigation property, but UserModel.Games would most likely throw an exception, as it is neither an entity type, nor does it implement ICollection<T> with T being an entity type, nor is it a primitive type from a database point of view). However, EF's work-everything-out-by-itself-magic doesn't cope too well with multiple relations between the same entity types, which is when the InversePropertyAttribute is needed.

一个演示问题的简单示例:

A quick example that demonstrates the problem:

class SomePrettyImportantStuff {
    [Key]
    public int ID { get; set; }

    public int OtherId1 { get; set; }

    public int OtherId2 { get; set; }

    [ForeignKey("OtherId1")]
    public virtual OtherImportantStuff Nav1 { get; set; }

    [ForeignKey("OtherId2")]
    public virtual OtherImportantStuff Nav2 { get; set; }
}

class OtherImportantStuff {
    [Key]
    public int ID { get; set; }

    public virtual ICollection<SomePrettyImportantStuff> SoldStuff { get; set; }

    public virtual ICollection<SomePrettyImportantStuff> BoughtStuff { get; set; }
}

这里,EF 知道它必须生成 2 个 FK,从 SomePrettyImportantStuffOtherImportantStuff,名称为 Id1Id2,但它无法分辨出哪个 ID 指的是从哪个实体出售它的实体,以及它是从哪个实体购买的.

Here, EF knows that it has to generate 2 FKs from SomePrettyImportantStuff to OtherImportantStuff with the names Id1 and Id2, but it has no way to tell which of the IDs refers to the entity where it was sold from and which is the one it was bought from.

如何解决循环引用问题

要解决这个问题,你的上下文类应该覆盖 OnModelCreating 并配置不应该在删除时级联的外键,如下所示:

To fix that problem, your context class should override OnModelCreating and configure the foreign keys which shouldn't cascade on delete accordingly, like this:

protected override void OnModelCreating(DbModelBuilder builder)
{
    builder.Entity<CityModel>().HasMany(c => c.Users).WithRequired(u => u.City)
           .HasForeignKey(u => u.CityId).WillCascadeOnDelete(value: false);

    // Add other non-cascading FK declarations here

    base.OnModelCreating(builder);
}

这篇关于实体框架代码优先中的关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆