【问题标题】:How to keep custom navigation properties after a model rebuild?模型重建后如何保留自定义导航属性?
【发布时间】:2012-04-23 13:03:24
【问题描述】:

我有几个从“用户”表到“报告”表的导航属性。生成的导航属性显然是这样访问的:

USER.REPORTs.Where(x => ...)
USER.REPORTs2.Where(x => ...)
USER.REPORTs3.Where(x => ...)

第一个是用户 createdId,第二个是 UserApprovedId 等等......基本的东西。

这些是极难解释的。如果不访问 EDMX 并检查导航属性,很难判断您正在导航哪个属性。

现在我知道我可以在属性管理器中创建自己的 End1/End2 导航属性,但如果重新创建模型,这些属性就会丢失。

有没有办法解决这个问题?

【问题讨论】:

  • 您能否添加更多信息以清楚地理解问题,希望我可以在这里添加一些帮助?
  • 它与 MVC 无关,绝对是 EF 问题!。
  • 你如何重建模型?如果您仅从数据库更新,则名称不会更改。您可以根据需要重命名导航属性,并通过该名称在代码中访问它们。

标签: c# entity-framework edmx


【解决方案1】:

我没有尝试过,但这里有一个想法:既然所有实体类型都是部分类,为什么不将 Visual Studio 生成的导航属性包装在另一个具有方便名称的属性中?

在您的设计器文件中,您将拥有如下内容:

public partial class MyEntity : EntityObject
{
    #region Navigation Properties
    public EntityCollection<MyOtherEntity> Other_Entities1
    {
        // ...
    }
    #endregion
}

然后您可以创建另一个文件来包装导航属性:

public partial class MyEntity
{
    public EntityCollection<MyOtherEntity> OtherEntities
    {
        get { return Other_Entities1;}
    }
}

您将在整个代码中使用上述属性,并且由于在 Visual Studio 生成 .edmx 文件时使用相同的逻辑,因此包装的属性不会更改。 即使包装的属性会更改其名称,您也需要在一个地方调整代码。

【讨论】:

  • 一开始似乎可行,但包装属性不能在 Linq to Entities 中使用...
【解决方案2】:

我不确定我是否正确理解了您的问题,但听起来您只是想要一种“更简洁”的方式来直接从 USER 对象访问 REPORTs.Where(...) LINQ 查询的结果.如果是这种情况,我建议像这样创建 USER 对象的扩展:

public static class UserExtensions
{
 public static List<REPORT> ReportsWithSomeCondition(this USER user)
 {
    return user.REPORTs.Where(...).ToList();
 }
}

你可以干净地调用它的方式是:

List<REPORT> results = USER.ReportsWithSomeCondition()

如果我完全错过了重点,请澄清您的问题,我将删除此答案。

【讨论】:

    【解决方案3】:

    我认为我遇到的问题与我从您的问题中了解到的一样。

    您希望保持导航属性名称尽可能清晰,但无论何时从 edmx 重新创建模型?!。

    其实我希望如果有更好的解决方案,但这里我正在做的:

    1. 将您在数据库中的关系命名为好名称,例如:FK_Users_CreateUserReport、FK_Users_ApprovedUserReport ... 或任何合适的名称,然后我们将导航属性重命名为 ApprovedUserReport 和 CreateUserReport 等等...李>
    2. 在您重新创建模型时创建一个帮助代码来执行,此代码将打开您的 edmx 文件并更新您想要的所有导航属性,如下所示:

      // file here is the path to your edmx file
      if (!string.IsNullOrEmpty(file))
      {
          var ns = XNamespace.Get("http://schemas.microsoft.com/ado/2008/09/edm");
          var doc = XDocument.Load(file);
          var list = (from xElem in doc.Descendants(ns + "NavigationProperty")
                      where xElem.Attribute("Name").Value.StartsWith("REPORTs"))
                      select xElem).ToList();
          foreach (var item in list)
          {
              var newName = item.Attribute("Relationship").Value.Split('_').LastOrDefault();
              if (!newName.Contains("."))
                  item.SetAttributeValue("Name", newName);
              else
              {
                  var ss = newName.Split('.').LastOrDefault();
              }
          }
          doc.Save(file);
          MessageBox.Show(list.Count.ToString());
      }
      

    如果你使用纯代码模式,那么这个问题就消失了,但在这种情况下,你应该手动让你的模型与你的数据库保持一致。

    【讨论】:

      【解决方案4】:

      您必须使用部分类机制将所有自定义实体代码放在单独的代码文件中。这允许生成生成的代码,而不会影响您的自定义代码。

      【讨论】:

        【解决方案5】:

        Wahid 的答案似乎是长期维护的最佳答案。我们考虑在部分类中实现接口属性,我们将其用作扩展的“伙伴类”并设置元数据链接。但是我们正在接口的 T4 模板中的属性仍然是公共的,它们应该是私有的。

        改进 Wahid 的建议;我们选择扩展它们,而不是改变我们命名外键关系的标准。

        FK_Users_Report_CreateUserReport 实际上是我们的解决方案。前 2 个值的标准命名约定得到维护,在更新模型代码中,您可以强制它仅更改带有第三个下划线和第三个值的导航属性名称。如果其他导航属性名称不遵循数据库中外键的标准命名约定,请确保它们不会影响任何其他导航属性名称。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-10-04
          • 2012-01-28
          • 2022-07-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-04
          • 2012-06-14
          相关资源
          最近更新 更多