我是MVC的新手,并且在Visual Studio 2015中将MVC 5用于ASP .NET C#Web应用程序。
代码优先。
我的目标:在代码中定义外键关系,让脚手架在数据库中创建键。
我很难做到这一点。如果可能的话,我不希望使用Fluent API。至少,我想了解1)为什么需要使用Fluent API,以及2)实际上如何使用它。
楷模
应用类型模型
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; }
}
}
现在,我希望创建其他一些使用anApplicationTypeID
作为外键的类。我创建了一个:
MVC5应用
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; }
它会生成,当我尝试通过“创建控制器”操作添加新的MVCApplication时:
EntityFramework.dll中发生类型'System.InvalidOperationException'的异常,但未在用户代码中处理。其他信息:无法将属性'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; }
错误:
EntityFramework.dll中发生类型'System.InvalidOperationException'的异常,但未在用户代码中处理。其他信息:类型'MVCModelFirstSample.Models.MVC5Application'的属性'ApplicationTypeID'上的ForeignKeyAttribute无效。在依赖类型“ MVCModelFirstSample.Models.MVC5Application”上找不到导航属性“ ApplicationType”。Name值应为有效的导航属性名称。
无论如何,那可能不是最好的主意。
通过定义类并提供外键,甚至可以通过代码优先生成外键关系吗?我试图在这里使事情尽可能简单。
理想情况下,我想使用键与数据库列名称不一定匹配。例如,我有一个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。
重命名模型中未定义的外键
如果您选择不为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);
}
经过大量的迁移(代码优先迁移)后:
我认为我取得了理想的结果:
但是,我必须诚实。在这一点上,整个过程还很不直观。
有没有更好的办法?
另外,如果有人对使用代码优先创建数据库表有任何其他参考,以便使它更容易理解,我将不胜感激。
谢谢
使用流畅的API,您可以使实体摆脱依赖于持久性的东西,并使模型保持在类库中,而无需依赖EF。我通常为DbContext创建一个第二项目,该项目包含配置,并且是唯一依赖于EF的项目。
如果声明导航属性(如最后使用ApplicationType属性所做的那样,EF会自动为您创建外键,这将使在对象模型中导航变得容易得多。Id用于数据库,在您的代码中要使用实类型的属性。
首先,您可以在EF Core文档中找到有关代码的更多信息。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句