将我的 ICollection 覆盖为我的 edmx 文件中的 IList 的最佳方法,在 asp.net MVC Web 应用程序中
Posted
技术标签:
【中文标题】将我的 ICollection 覆盖为我的 edmx 文件中的 IList 的最佳方法,在 asp.net MVC Web 应用程序中【英文标题】:Best appraoch to override my ICollection to be IList inside my edmx file, inside asp.net MVC web application 【发布时间】:2017-11-11 15:24:51 【问题描述】:我正在开发一个 ASP.NET MVC Web 应用程序。我已经使用 ADO.NET Entity Framework 映射了我的数据库表,它生成了一个.edmx
文件。现在生成的.edmx
文件的限制之一是所有代表父子关系的集合都将被定义为ICollection
。例如我有这个问题模型类:-
public Question()
this.Anwers = new HashSet<Anwer>();
public int Id get; set;
public string QuestionDesc get; set;
public int Order get; set;
public bool Active get; set;
public virtual ICollection<Anwer> Answers get; set;
这是答案模型:-
public partial class Anwer
public Anwer()
this.UserFormsAnswers = new HashSet<UserFormsAnswer>();
public int Id get; set;
public string AnwerDesc get; set;
public int QuestionID get; set;
public bool Correct get; set;
public virtual Question Question get; set;
public virtual ICollection<UserFormsAnswer> UserFormsAnswers get; set;
现在ICollection
与IList<>
相比的问题是我无法使用索引器来获取与问题相关的答案的值。如果我有IList<>
而不是ICollection<>
,我可以索引问题的答案。
所以我的问题是将我的public virtual ICollection<Anwer> Answers get; set;
覆盖为public virtual IList<Anwer> Answers get; set;
的最佳方法是什么?当然应该避免修改自动生成的.edmx
文件,因为如果我重新映射我的数据库表,我的修改将被覆盖..
【问题讨论】:
你能分享你的答案模型吗 @hasan ok 更新了。 是否需要索引仍然值得怀疑。在您的示例中,@for
可以轻松替换为@foreah
,从而消除了索引的需要。 EF 模型集合导航属性根据定义是无序的,因此 ICollection<T>
比 IList<T>
更适合(从生成的代码中可以看出,它允许实现使用更高效的 Add
/ Remove
/ Contains
HashSet<T>
类提供的实现,如果需要暴露IList<T>
,则无法实现。
您正在编辑数据,因此您永远不应该在视图中使用您的数据模型。规则 1:始终使用视图模型(并且视图模型包含 IList<T>
属性)。另请注意,您可以使用与IEnumerable<T>
一起使用的自定义EditorTemplate
,并且不需要IList<T>
- 请参阅this answer,但您不能使用@IvanStoev 建议的foreach
循环
暂时忘记讨论为什么以及是否需要公开IList
而不是ICollection
。当前答案的第一部分提供了您问题的直接解决方案 - *modify T4 templates 用于从edmx
生成实体模型类。你还需要什么——究竟如何修改.tt
文件,要修改哪个.tt
文件?
【参考方案1】:
如果您确实需要将所有ICollection
对象修改为IList
对象,那么执行此操作的正确位置是在您的T4 模板中。它们是 edmx 中的“.tt”文件。这些是用于生成项目其余部分使用的代码文件的模板。每当您更新 edmx 时,对这些模板所做的任何修改都会在您的项目中传播。
也就是说,我会质疑您是否真的需要进行此更改。最好让数据库的返回类型尽可能通用,然后将其缩小到要使用它的 List(或其他)。
【讨论】:
@Nesoras 现在我提到使用ICollection
实现外键,将不允许我应用索引.. 而使用代码优先方法将外键关系实现为List
或父对象上的ILIST
.. 所以我认为使用LIST
而不是ICollection
是错误的,因为在代码优先的方法中,所有FK 都将在父对象内实现为ILIST
。
您能就此提出建议吗?
@johnG 答案的第一部分是涵盖如何做你想做的事。我看不出你还需要什么。
@johnG 正如我在最初的回答中所说,如果您希望返回类型永久不同,则可以修改 T4 模板。至于为什么要将其保留为ICollection
,请考虑您希望在Queue<T>
中使用EF 返回的数据的可能性。由于Queue<T>
实现了ICollection
而不是IList
,因此在对T4 模板进行更改后您将无法这样做。最好将 EF 返回的数据保留为 ICollection
,然后在您需要使用它的集合上调用 .ToList(),例如在您上面引用的前端视图模型中。
听起来您将视图直接绑定到由 edmx 创建的模型对象。这就是你问题的根源所在。相反,您应该有一个 Question
对象,该对象由您的 edmx 创建,上面有一个 ICollection<Answer>
。然后在你的前端项目中你应该有一个QuestionViewModel
对象,上面有一个IList<AnswerViewModel>
。然后,您可以将数据库模型投影到视图模型上,并在表示层使用视图模型数据类型,而不是用表示问题污染您的数据层。【参考方案2】:
ToList
您的收藏并使用 List.. 它实现了 IList 并具有索引器方法 []
例如
@for (var i = 0; i < m.Answers.Count; i++)
@html.EditorFor(m => m.Anwers.ToList()[i].Id)
当然,这个例子很愚蠢,因为每次 for 循环都会强制转换为列表。但是您可以在 for 循环之前轻松地将答案列在列表中。最好的办法是使用视图模式。我可以发布看起来像的代码。你可以先用剃须刀做这样的事情
@List<Answers> answers = m.Anwers.ToList()
@for (var i = 0; i < answers.Count; i++)
@Html.EditorFor(answers => answers[i].Id)
顺便说一句,你绝对可以用 foreach 循环和 iCollection 做同样的事情。
【讨论】:
【参考方案3】:在 IList 中是派生自 ICollection。在 EDMX 文件生成的模型中 首先我们改变
public Question()
this.Anwers = new HashSet<Anwer>();
public int Id get; set;
public string QuestionDesc get; set;
public int Order get; set;
public bool Active get; set;
public virtual ICollection<Answer> Answers get; set;
首先我们需要改变 Hashset<Answer> to List<Answer>()
和
public virtual ICollection<Answer> Answers get; set;
到
public virtual IList<Answer> Answers get; set;
如果我们改变了它就可以正常工作
Sample Image With ICollection to IList Change
Sample Image for Fetching Record With Indexer with out Exception
在 NHibernate ORM 中,使用 IList 替代 ICollection 进行关系, 使用前请检查以下链接
Why use ICollection and not IEnumerable or List on many-many/one-many relationships?
如下更新 Model.tt 文件
将 ICollection 更改为 IList
navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("IList<" + endType + ">") : endType,
HashSet 改为 List
this.<#=code.Escape(navigationProperty)#> = new List<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>();
一旦您像上面一样更新了 model.tt 文件,从 DB 重新映射 EDMX 更新时不会出现任何问题。
【讨论】:
下次他重新生成他的 EDMX 文件时会发生什么?以上是关于将我的 ICollection 覆盖为我的 edmx 文件中的 IList 的最佳方法,在 asp.net MVC Web 应用程序中的主要内容,如果未能解决你的问题,请参考以下文章
无法将我的 mat4 转换矩阵解析为我的 opengl 着色器?
如何将我的 SwiftUI 视图的 @State 交换为我的视图模型 @Published 变量?
EF 6 codde first - 一对多映射 - ICollection始终为null