使用实体框架代码优先,我是否需要拥有我的领域贫血模型?
使用实体框架代码优先我必须将所有属性公开才能生成数据库,这意味着使用实体框架代码优先方法我被迫拥有 贫乏的领域与丰富的模型混合在一起?因为不需要公开的属性必须公开。
例如:
使用丰富的模型,这在实体框架中将不起作用:
public class Car
{
private int _actualPosition;
public void Accelerate()
{
this._actualPosition += 10;
}
}
要工作,我们需要将 _actualPosition
公开:
public class Car
{
public int ActualPosition { get; set; }
public void Accelerate()
{
this.ActualPosition += 10;
}
}
现在实体 IMO 很丑陋,因为我有一个方法这会在属性中添加 + 10 并同时将其公开,我不希望该属性公开。
另一个例子:
想象一下我想要一种多对多的关系,但只有一种方式,例如:
public class User
{
public long Id { get; set; }
public string Name { get; set; }
public IList<Role> Roles { get; set; }
}
public class Role
{
public long Id { get; set; }
public string Name { get; set; }
}
我如何进行多对多关系与该模型的关系?据我所知,我不可能建立双向关系:
public class User
{
public long Id { get; set; }
public string Name { get; set; }
public IList<Role> Roles { get; set; }
}
public class Role
{
public long Id { get; set; }
public string Name { get; set; }
public IList<User> Users { get; set; }
}
通过这个模型,我将能够建立多对多关系:
modelBuilder.Entity<User>()
.HasMany(x => x.Roles)
.WithMany(y => y.Users);
我是对的吗?如果是,实体框架不让我满意。
“另一个示例”与@Slauma的答案配合使用:
modelBuilder.Entity<User>()
.HasMany(x => x.Roles)
.WithMany()
.Map(a =>
{
a.MapLeftKey("UserId");
a.MapRightKey("RoleId");
a.ToTable("UserRoles");
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您的“另一个例子”不正确。您不必被迫将关系的两端公开为模型类中的属性。在您的示例中,您可以删除
public IList;用户{得到;放; }
从您的Role
类中定义映射,如下所示:对于一对多关系也是如此。始终存在无参数
With...
重载、WithMany()
、WithRequired()
、WithOptional()
等来定义模型中两端未公开的关系的映射。Your "Another example" is not correct. You are not forced to expose both ends of a relationship as properties in your model classes. In your example you can remove
public IList<User> Users { get; set; }
from yourRole
class and define the mapping like so:This is the case also for one-to-many relationships. There is always a parameterless
With...
overload,WithMany()
,WithRequired()
,WithOptional()
, etc. to define mappings for relationships where not both ends are exposed in the model.您可以像这样设置您的
Car
实体:这会强制修改
ActualPosition
属性以使用专门的Accelerate
方法。使用此样式的副作用是您的 Accelerate 方法不可测试。您也可以这样设置:
但是,如果不使用反射,这种方法无法直接测试。
You can setup your
Car
Entity like this:This forces modification of the
ActualPosition
property to use the specializedAccelerate
method. A side effect of using this style is that yourAccelerate
method is not testable.You can also set it up like this:
However this approach isn't directly testable without using reflection.
简短回答:除非框架支持它,否则如果您尝试同时使用业务规则和公共属性,那么您将陷入在此类中塞入太多内容的困境。
长答案:
我曾经使用过一个非常像这样的系统,基本上我意识到测试和封装的最佳方法是用我真正的域类包装这个类。
当我之前这样做时,我能够让较低级别的 Persistence 类实现一个接口,我的测试可以使用该接口注入 Business 类以进行简单测试,而无需与数据库对话。
像这样的系统,您的业务类位于一个“层”,而您的持久性类位于另一“层”,您可以很容易地建立一对多关系,只需将其构建到从持久性构建业务类的任何内容中即可类:
抱歉,语法可能不完美,这是我能记得的从 VB 音译为 C# 的最好结果;)
Short Answer: Unless the framework supports it, you are stuck trying to jam too much into this class if you attempt with both business rules AND public properties.
Long Answer:
I once used a system very like this, and basically I came to the realization that the best way for testing and encapsulation was to wrap this class with my real domain class.
When I did this before, I was able to then have my lower level Persistence class implement an interface that could be used by my tests to inject into the Business class for simple testing without having to talk to the database.
A system like this, with your business classes on one "layer" and your persistence classes on another "layer" you can pretty easily have one-to-many relationships, it just has to be built into whatever builds your business classes out of persistence classes:
Sorry, the syntax might not be perfect, that's the best I can remember it transliterating from VB into C# ;)
我相信您正在寻找的是以下内容:
单元测试如下:
I believe what you are looking for is the following:
The unit test is below :
是的,您发布的代码是贫血模型。此外,我什至不会称其为正确的面向对象代码。根本没有封装,对象只是数据容器。看起来您选择的 ORM 限制了您的域实现选择。无论如何,NHibernate 允许您直接映射字段(即使这些字段是只读的)。它不要求对象具有属性。例如:
可以映射为:
Yes, the code that you posted is an Anemic Model. Furthermore, I would not even call it a proper object oriented code. There is simply no encapsulation and objects are just a data containers. Looks like your ORM of choice is limiting your domain implementation choices. For what it's worth, NHibernate allows you to map fields directly (even if these fields are readonly). It does not require objects to have properties. For example:
Can be mapped as: