2011-09-21 89 views
3

我正在EF 4.1的第一步。因为我使用的是NHibenate,所以在我看来,代码优先的方法是最好的。我对于一对多(或多对一)真实性的良好映射存在问题。假设我有两个实体:实体框架一对多关系代码

class ClientModel 
{ 
    int ClientID; 
    string Name; 
    virtual IList<OrderModel> Orders; 
} 

class OrderModel 
{ 
    int OrderID; 
    string Details; 
    virtual ClienModel Client; 
} 

当我这样离开时,生成数据库时出现错误 - 表中的键缺失。我想通过将密钥的名称更改为ID(但它不符合我的命名约定)或通过添加[Key]注释来修复它。即使我添加了这个注解,表名仍然是错误的 - 就像类的名字,但是用's'。 所以我试图使用流利的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"); 
    } 
} 

数据库中表之间的关系增加了一倍。 使用代码优先方法进行一对多关系的正确方法是什么?我是朝着一个好的方向思考还是错误的方法?

编辑

OK,我已经在路上@Eranga表现做了,但仍是一个问题。当我从数据库获取客户端时,其Orders属性为空(但在数据库中它有一些Order.ClientID == Client.ClientID的订单)。

+0

我测试了我的答案给出的配置和正常工作。确保'订单'是一个财产,而不是一个领域。 – Eranga

+0

尝试'虚拟列表订单;'而不是'虚拟IList 订单;' –

回答

6

您需要映射参与关系的两个属性。您需要将ClientID列添加到订单表。

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).WithRequired(o => o.Client) 
      .Map(p => p.MapKey("ClientID")).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.ToTable("Orders"); 
    } 
} 

从一个实体配置关系就足够了。

+1

“您需要映射两个参与关系的属性,您需要将ClientID列添加到订单表。 你到底意味着什么? – rideronthestorm

+0

@rideronthestorm'ClientModel'中的Orders'属性和'OrderModel'中的'Client'属性作为关系的两个参与者。 – Eranga

+1

我还是不明白。我不是在映射他们两个吗?也许你可以发布完整的代码? 为什么我需要OrderID(OrderModel?)中的ClientID? – rideronthestorm

0

这可能有助于(它帮助我,当我无法弄清楚如何工作):

如果你将有类是这样的:

class ClientModel 
{ 
    int ClientId; 
    string Name; 
} 

class OrderModel 
{ 
    int OrderId; 
    string Details; 
    int ClientId; 
} 

那么这将是2个表在你的数据库中“不会”通过外键相互连接(它们将通过OrderModel中的ClientId连接),并且可以从数据库中获得诸如“GetAllOrdersWithSomeClientId”和“GetTheClientNameForSomeClientId”之类的数据。但是,当你从数据库中删除Client时会出现问题。因为那样仍然会有一些Orders,其中将包含ClientId,该表不存在于Client表中,并且会导致数据库中出现异常。

需要virtual List<OrderModel> Orders;(在ClientModel)和virtual ClienModel Client;(在OrderModel)来创建关系aka。表ClientModelOrderModel之间的外键。

有一件事我仍然不确定。这是OrderModel中的int ClientId;。我想它必须与ClientModel中的ClientId具有相同的名称,以便实体框架知道外键必须连接哪两个属性。如果有人能够详细解释这一点会很好。

而且,要把它放到你的DbContext的构造函数,如果事情souldn't工作:

this.Configuration.ProxyCreationEnabled = false; 
this.Configuration.LazyLoadingEnabled = false;