【问题标题】:How To Change Navigation Property Names Into Meaningful Names如何将导航属性名称更改为有意义的名称
【发布时间】:2012-11-23 12:14:01
【问题描述】:

我在 Entity Framework 5 中使用 Database First。我们有两个表(大大简化):

  • 地址
    • 街道
    • 城镇(等)
  • 客户
    • 姓名
    • 帐单地址
    • 收货地址
    • 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 会抱怨以下错误:

LINQ to Entities 不支持指定的类型成员“BillingAddress”。仅支持初始化程序、实体成员和实体导航属性。

还有其他方法可以在客户对象中实现有意义的名称吗?

这是我最后想要的:

var j = myCustomer.BillingAddress;
var k = myCustomer.BillingAddress.Street;
var l = myCustomer.BillingAddress.Town; // etc.

【问题讨论】:

    标签: c# entity-framework entity-framework-5 ef-database-first


    【解决方案1】:

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

    【讨论】:

    • 好吧,它只有在您不删除实体并将其读取到您的模型时才有效,如果您想将模型与数据库同步会发生什么情况。 f.e.刷新时删除数据库中的列不会在模型中执行相同操作
    • 不幸的是,EF 设计器并不那么可靠。通常我们只是删除整个模型并重新创建它,因为尝试进行更新会破坏它。因此,我们无法使用此选项。
    • 如果我对模型进行更改,它是否也会对现有的数据库和代码类进行相应的更改? ...我真的很想要那个。
    【解决方案2】:

    您可以将属性添加到部分类中,这些属性将成为属性 Address1、Address2 等的访问器。

    例子:

    public partial class Customer : EntityObject
    {
        public Address BillingAddress
        {
             get 
             {
                 return this.Address;
             }
             set 
             {
                  this.Address = value;
             }
        }
    }
    

    更新:它不适用于 linq to 实体。 恐怕这是数据库优先方法的限制。这也是我们使用 EF Code First 的原因之一。在 Code First 中,您可以完全控制实体映射。 (Code First 是代码中的映射,不代表你不想用这段代码生成你的db)。

    【讨论】:

    • 如果您可以确定 EF 生成的名称与真实数据库名称之间的映射关系,则该方法有效。即如果 .Address2 始终是 AltDeliveryAddress 则没关系,但它似乎不是很安全。
    • 实际上不,当我尝试在 LINQ 中使用它时,它不起作用。这是我的代码: var customersInSeattle = cs.Where(c => c.DeliveryAddress.Town == "Seattle");我收到此错误:LINQ to Entities 不支持指定的类型成员“DeliveryAddress”。仅支持初始化器、实体成员和实体导航属性。
    • 是的,这是真的……恐怕这是数据库优先方法的限制。这也是我们使用 EF Code First 的原因之一。在 Code First 中,您可以完全控制实体映射。 (Code First的意思是代码中的映射,不代表你不想用这段代码生成你的db)。
    • 我会奖励你正确的答案,因为你最接近帮助。我们将在下一个主要版本中考虑使用 Code First。非常感谢。
    【解决方案3】:

    我知道这有点陈旧,但处理这种情况的最简单/最好的方法似乎是利用 EF5 电动工具“首先逆向工程代码”。

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

    它为您提供了代码优先映射的所有优点以及数据库优先对象创建的简单/方便。

    【讨论】:

      【解决方案4】:

      这里描述了一个解决方案:

      Improve navigation property names when reverse engineering a database

      您可以将代码生成模板(*.tt 文件)包含到您的项目中。按照链接中的说明修改它们。示例在这里:https://github.com/markuspeter/EFPowerToolsTemplates(检查分支是否有更改)

      然后你的命名可以生成更好的名字。

      【讨论】:

      • 始终建议在链接资源中包含代码 sn-ps/最合适的一两个段落,即使只是为了防止链接腐烂。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-18
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-24
      相关资源
      最近更新 更多