实体框架一对多关系代码优先
我正在 EF 4.1 中迈出第一步。因为我使用的是 NHibenate,所以代码优先的方法在我看来是最好的方法。我在一对多(或多对一)关系的良好映射方面遇到问题。假设我有 2 个实体:
class ClientModel
{
int ClientID;
string Name;
virtual IList<OrderModel> Orders;
}
class OrderModel
{
int OrderID;
string Details;
virtual ClienModel Client;
}
当我这样保留它时,生成数据库时出现错误 - 表中的键丢失。我发现我可以通过将键的名称更改为 ID(但这不符合我的命名约定)或添加 [Key] 注释来修复它。即使我添加此注释,表的名称仍然是错误的 - 就像类名称一样,但带有“s”。 所以我尝试使用 Fluent API - 我做了映射。但是,如果我像这里一样设置映射:
class ClientMapping
{
ClientMapping()
{
this.HasKey(e => e.ClientID).Property(e => e.ID).HasColumnName("ClientID");
this.Property(e => e.Name).HasColumnName("Name");
this.HasMany(e => e.Orders).WithOptional().Map(p => p.MapKey("OrderID")).WillCascadeOnDelete();
this.ToTable("Clients");
}
}
class OrderMapping
{
OrderMapping()
{
this.HasKey(e => e.OrderID).Property(e => e.OrderID).HasColumnName("OrderID");
this.Property(e => e.Details).HasColumnName("Details");
this.HasRequired(e => e.Client).WithMany().Map(p=>p.MapKey("Client")).WillCascadeOnDelete(false);
this.ToTable("Orders");
}
}
数据库中表之间的关系会加倍。 使用代码优先方法建立一对多关系的正确方法是什么?我的思考方向是好的还是错误的?
编辑
好的,我已经按照@Eranga所示的方式完成了,但仍然存在问题。当我从数据库获取 Client 时,其 Orders 属性为 null (但在数据库中它有一些 Order.ClientID == Client.ClientID 的订单)。
I am having my first steps in EF 4.1. Because I was using NHibenate, the code first approach seems to me as the best one. I have problem with good mapping of one-to-many (or many-to-one) realtionship. Let's say I have 2 entities:
class ClientModel
{
int ClientID;
string Name;
virtual IList<OrderModel> Orders;
}
class OrderModel
{
int OrderID;
string Details;
virtual ClienModel Client;
}
When I leave it like that, there is an error while generating database - keys in tables are missing. I figured out I can fix it by changing names of the keys to ID (but it's not OK with my naming convention) or by adding [Key] annotation. Even if I add this annotation, still the names of tables are wrong - just like classes names but with 's'.
So I tried to use fluent API - I made mappings. But if I set mappings just like here:
class ClientMapping
{
ClientMapping()
{
this.HasKey(e => e.ClientID).Property(e => e.ID).HasColumnName("ClientID");
this.Property(e => e.Name).HasColumnName("Name");
this.HasMany(e => e.Orders).WithOptional().Map(p => p.MapKey("OrderID")).WillCascadeOnDelete();
this.ToTable("Clients");
}
}
class OrderMapping
{
OrderMapping()
{
this.HasKey(e => e.OrderID).Property(e => e.OrderID).HasColumnName("OrderID");
this.Property(e => e.Details).HasColumnName("Details");
this.HasRequired(e => e.Client).WithMany().Map(p=>p.MapKey("Client")).WillCascadeOnDelete(false);
this.ToTable("Orders");
}
}
the relation betweene tables in database is doubled.
What is the proper way to do one-to-many relationship using code-first approach? Am I thinking in a good direction or is it a wrong approach?
EDIT
OK, I have done it in the way @Eranga showed, but there is still a problem. When I'm getting Client from database, its Orders property is null (but in database it has some Orders with Order.ClientID == Client.ClientID).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要映射参与关系的两个属性。您需要将
ClientID
列添加到 Orders 表中。从一个实体配置关系就足够了。
You need to map both properties participating in the relationship. You need to add
ClientID
column to Orders table.Configuring the relationship from one entity is sufficient.
这可能会有所帮助(当我无法弄清楚这是如何工作时,它对我有帮助):
如果您有这样的类:
那么这将代表数据库中的两个表,它们“不会”通过以下方式相互连接外键(它们将通过
OrderModel
中的ClientId
连接),您可以从数据库获取诸如“GetAllOrdersWithSomeClientId”和“GetTheClientNameForSomeClientId”之类的数据。但是,当您从数据库中删除Client
时,就会出现问题。因为这样仍然会有一些Orders
包含ClientId
,而该Client
不再存在于Client
表中,这会导致异常在你的数据库中。虚拟列表需要 Orders;
(在ClientModel
中)和virtual ClienModel Client;
(在OrderModel
中)来创建关系。表ClientModel
和OrderModel
之间的外键。有件事我仍然不确定。这是
OrderModel
中的int ClientId;
。我猜想它必须与 ClientModel 中的 ClientId 具有相同的名称,以便实体框架知道外键必须连接哪两个属性。如果有人可以详细解释这一点,那就太好了。另外,如果某些东西不起作用,请将其放入 DbContext 构造函数中:
This may help (it helped me, when i couldn't figure out how this works):
If you would have the classes like this:
Then this would represent 2 tables in your database which "wouldn't" be connected with each other via a foreign key (they would be connected via the
ClientId
in theOrderModel
) and you could get data like "GetAllOrdersWithSomeClientId" and "GetTheClientNameForSomeClientId" from the database. BUT problems would arise when you would delete aClient
from the database. Because then there would still be someOrders
which would contain aClientId
which doesn't exist in theClient
table anymore and that would lead to anomalies in your database.The
virtual List<OrderModel> Orders;
(in theClientModel
) andvirtual ClienModel Client;
(in theOrderModel
) are needed to create the relation aka. the foreign key between the tablesClientModel
andOrderModel
.There is one thing about which i'm still not sure about. Which is the
int ClientId;
in theOrderModel
. I guess that it has to have the same name as theClientId
in theClientModel
so that the entity framework knows which 2 attributes the foreign key has to connect. Would be nice if someone could explain this in detail.Also, put this into your DbContext constructor if something souldn't work: