如何将导航属性名称更改为有意义的名称

7
我在使用Entity Framework 5的Database First。我们有两个表(大量简化):
地址(Addresses) -街道(Street) -城镇等
客户(Customers) -姓名(Name) -账单地址(BillingAddress) -交货地址(DeliveryAddress) -备用送货地址(AltDeliveryAddress)
当我们使用Visual Studio将数据库导入到EF(“从数据库更新模型”)时,我们得到如下代码:
Customer myCustomer;
var a = myCustomer.Address;
var b = myCustomer.Address1;
var c = myCustomer.Address2;

我希望你能够提供如下内容:
var a = myCustomer.BillingAddress;
var z = myCustomer.BillingAddress.Street; // etc.

我可以在设计师中编辑模型,更改导航属性以获得正确的名称。然而,这并不是可行的解决方案,因为我们每次对数据库进行更改时都需要重新构建模型。

我尝试过的一种选择是创建一个部分类,像这样(代码从现有的MyModel.Designer.cs复制,只更改了属性名称):

public partial class Customer : EntityObject
{
    [EdmRelationshipNavigationPropertyAttribute("MyModel", "FK_Customers_Addresses_BillingAddress", "Address")]
    public Address BillingAddress
    {
        get {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<LookupItem>("MyModel.FK_Customers_Addresses_BillingAddress", "Address").Value;
        }
        set {
            ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<LookupItem>("MyModel.FK_Customers_Addresses_BillingAddress", "Address").Value = value;
        }
    }
}

然而,当我运行时,出现以下错误:

概念类型“MyModel.Customer”的成员数与对象侧类型“MyNamespace.DataModel.Customer”的成员数不匹配。确保成员数量相同。

我尝试使用 [NotMapped()] 属性,但没有任何区别。如果我删除 [EdmRelationshipNavigationPropertyAttribute...] 属性,则 Linq 会报以下错误:

指定的类型成员“BillingAddress”在 LINQ to Entities 中不受支持。只支持初始化项、实体成员和实体导航属性。

有没有其他方法可以在 Customers 对象中实现有意义的名称?
下面是最终想要实现的效果:
var j = myCustomer.BillingAddress;
var k = myCustomer.BillingAddress.Street;
var l = myCustomer.BillingAddress.Town; // etc.
4个回答

6

您可能不需要担心这个问题。在模型设计器中更改属性名称后,EF将记住自定义命名。它不会被后续更新覆盖。


4
只要您不将实体从模型中移除并重新添加,这种方法就有效。但是如果您想要将模型与数据库同步,那么可能会出现这种情况。例如,在数据库中删除列时,在刷新时不会在您的模型中删除相同的列。请注意不要改变原来的意思。 - Mohnkuchenzentrale
2
不幸的是,EF设计师并不是很可靠。通常我们只能删除整个模型并重新创建它,因为尝试进行更新会破坏它。因此,这个选项对我们来说不可用。 - andrewpm
如果我对模型进行更改,它是否会相应地更改现有的数据库和代码类?...我真的很想要那个。 - Sana.91

2
你可以为你的部分类添加属性,这些属性将作为访问器来访问 Address1Address2 等属性。
示例:
public partial class Customer : EntityObject
{
    public Address BillingAddress
    {
         get 
         {
             return this.Address;
         }
         set 
         {
              this.Address = value;
         }
    }
}

更新:它不能与linq to entities一起使用。 恐怕这是数据库优先方法的限制。这是我们使用EF Code First的原因之一。在Code First中,您可以完全控制实体映射。(Code First表示在代码中进行映射,这并不意味着如果您不想要它,您的db将从此代码生成)。

如果您可以确定EF生成的名称与实际数据库名称之间的映射关系,那么这将起作用。也就是说,如果.Address2始终是AltDeliveryAddress,那么这是可以的,但这似乎不太安全。 - andrewpm
实际上不行,当我尝试在LINQ中使用它时,它不起作用。 这是我的代码:var customersInSeattle = cs.Where(c => c.DeliveryAddress.Town == "Seattle");我得到了这个错误: 指定的类型成员“DeliveryAddress”在LINQ to Entities中不受支持。仅支持初始化程序、实体成员和实体导航属性。 - andrewpm
是的,这是真的...我很害怕这是数据库优先方法的限制。这是我们使用EF Code First的原因之一。在Code First中,您可以完全控制实体映射。(Code First意味着在代码中进行映射,如果您不想要它,它并不意味着您的数据库将从此代码生成)。 - Kirill Bestemyanov
我会授予你正确的答案,因为你最接近帮助了。我们将在下一个主要版本中考虑使用Code First。非常感谢。 - andrewpm

0

1
建议始终包含代码片段/链接资源中最合适的一两段,即使只是为了防止链接失效。 - bardzusny

0

我知道这可能有点旧,但似乎处理这种情况最简单/最好的方法是利用EF5强大的工具“反向工程代码优先”。

http://msdn.microsoft.com/en-us/data/jj200620

它提供了代码先行映射的所有优点,同时又具备数据库先行对象创建的简便性和便利性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接