我是MVC的新品牌,我在Visual Studio 2015中使用MVC 5作为ASP .NET C#Web应用程序。
代码优先。
我的目标:在代码中定义外键关系,让脚手架在数据库中创建键。
我很难做到这一点。如果可能,我宁愿不使用Fluent API。至少,我想了解1)为什么我需要使用Fluent API,2)实际上如何使用它。
模型
ApplicationType模型
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
namespace MVCModelFirstSample.Models
{
public class ApplicationType
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ApplicationTypeID { get; set; }
[Required]
[MaxLength(50)]
public string ApplicationTypeShortDescription { get; set; }
[Required]
[MaxLength(500)]
public string ApplicationTypeLongDescription { get; set; }
[Required]
public int CreatedByUserID { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime CreatedDate { get; set; }
[Required]
public int ModifiedByUserID { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime ModifiedDate { get; set; }
}
}
现在,我希望创建一些使用ApplicationTypeID
作为外键的其他类。我创造了一个:
MVC5Application
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
namespace MVCModelFirstSample.Models
{
public class MVC5Application
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int MVC5ApplicationID { get; set; }
[Required]
public int ApplicationTypeID { get; set; }
[Required]
[MaxLength(500)]
public string MVC5ApplicationDescription { get; set; }
[Required]
public int CreatedByUserID { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime CreatedDate { get; set; }
[Required]
public int ModifiedByUserID { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime ModifiedDate { get; set; }
}
}
本身,这些模型可以工作,我可以构建控制器,数据库可以正确生成等等。但是,数据库中的MVC5Application表中的ApplicationTypeID与ApplicationType表之间没有链接。
基于我的一些研究,有一些迹象表明可能会创建自动生成的外键关系,但目前尚不清楚。它没有。
因此,我首先想到的是在[ForeignKey("ApplicationTypeID")]
类的属性定义上方添加MVCApplication
属性。
对我来说这样做是有道理的(无论它是否真的合情合理是另一回事)。无论如何,片段:
namespace MVCModelFirstSample.Models
{
public class MVC5Application
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int MVC5ApplicationID { get; set; }
[Required]
[ForeignKey("ApplicationTypeID")]
public int ApplicationTypeID { get; set; }
它构建,当我尝试通过Create controller action添加新的MVCApplication时:
发生了'System.InvalidOperationException'类型的异常 EntityFramework.dll但未在用户代码中处理 信息:属性'ApplicationTypeID'不能配置为 导航属性。该属性必须是有效的实体类型和 该属性应该有一个非抽象的getter和setter。对于 集合属性类型必须实现ICollection所在的T 是一种有效的实体类型。
这是我感到困惑的地方。我发誓,我已经搜索,搜索和搜索。我找到了不同的建议,但对于我如何设置它没有任何明确的建议。
一种可能的选择是将类声明为键。我猜,也许,它会自动检测类中的ID并使用它?不确定,但嘿,值得一试,对吗?看起来你可以在这些字符串值中放置任何你想要的东西。在使用之前,没有人会抱怨。
public class MVC5Application
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int MVC5ApplicationID { get; set; }
[Required]
[ForeignKey("ApplicationType")]
public int ApplicationTypeID { get; set; }
错误:
发生了'System.InvalidOperationException'类型的异常 EntityFramework.dll但未在用户代码中处理 信息:属性'ApplicationTypeID'上的ForeignKeyAttribute 类型'MVCModelFirstSample.Models.MVC5Application'无效。 在找不到导航属性'ApplicationType' 依赖类型'MVCModelFirstSample.Models.MVC5Application'。名字 value应该是有效的导航属性名称。
无论如何,这可能不是最好的主意。
是否可以通过代码优先通过定义类和提供外键来生成外键关系?我想尽量让事情变得简单。
理想情况下,我想使用不一定匹配的数据库列名称的密钥。例如,我有一个User表,其UserID值与其他表中的CreatedByUserID相关。
说到这里,我开始使用Fluent API。
我遇到了麻烦。我的DbContext是什么,我需要找到并使用?我想,我终于想通了。
因为我使用了Internet身份验证,所以我有IdentityModel.cs,其中包含以下内容:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false)
{
}
...然后我会添加我的覆盖:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
在覆盖中,我会添加我的Fluent API。
根据Configuring Relationships with the Fluent API:
重命名未在模型中定义的外键
如果您选择不在CLR类型上定义外键,但想要 指定数据库中应该包含的名称,执行以下操作:
modelBuilder.Entity<Course>()
.HasRequired(c => c.Department)
.WithMany(t => t.Courses)
.Map(m => m.MapKey("ChangedDepartmentID"));
没有。我无法直接使用此代码。我要做的就是坐下来查看示例类并将它们与我自己的类联系起来。我意识到我对这些东西应该如何工作有一些基本的误解或理解。
我必须修改我的课程:
public class ApplicationType
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ApplicationTypeID { get; set; }
[Required]
[MaxLength(50)]
public string ApplicationTypeShortDescription { get; set; }
[Required]
[MaxLength(500)]
public string ApplicationTypeLongDescription { get; set; }
[Required]
public int CreatedByUserID { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime CreatedDate { get; set; }
[Required]
public int ModifiedByUserID { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime ModifiedDate { get; set; }
public virtual ICollection<MVC5Application> Applications { get; set; }
}
public class MVC5Application
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int MVC5ApplicationID { get; set; }
//[Required]
//[ForeignKey("ApplicationType")]
//public int ApplicationTypeID { get; set; }
public virtual ApplicationType ApplicationType { get; set; }
[Required]
[MaxLength(500)]
public string MVC5ApplicationDescription { get; set; }
[Required]
public int CreatedByUserID { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime CreatedDate { get; set; }
[Required]
public int ModifiedByUserID { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime ModifiedDate { get; set; }
}
现在,按照关于Fluent API的文章中列出的模式:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MVC5Application>()
.HasRequired(r => r.ApplicationType)
.WithMany(w => w.Applications)
.Map(m => m.MapKey("ApplicationTypeID"));
base.OnModelCreating(modelBuilder);
}
经过大量迁移(Code First Migrations)工作后:
我得到了我想要的结果,我想:
但是,我必须诚实。此时,整个过程非常不直观。
有更好的方法吗?
此外,如果任何人对使用代码优先创建数据库表有任何其他参考,以便更容易理解,我会很感激。
谢谢
答案 0 :(得分:0)
使用流畅的API,您可以使您的实体免于依赖于持久性的内容,并将您的模型保存在类库中,而不依赖于EF。我通常为DbContext创建第二个项目,它包含配置,是唯一取决于EF的项目。
如果您声明导航属性(就像最后使用ApplicationType属性一样),EF会自动为您创建外键,这样可以更轻松地浏览对象模型.Id&#39用于数据库,在你的代码中,你想使用真实类型的属性。
您可以在EF Core documentation中找到有关代码的详细信息。