7

编辑- 清理问题以更好地反映实际问题:

我正在使用 SQLMetal 从我们的 SQL Server db 生成数据库类。最近,我需要添加一个具有多个指向同一个表的外键的表。使用 LINQPad 来处理新表,我能够访问两个外键的属性,如下所示:

  • 记录.FK_AId
  • 记录.FK_BId
  • 记录.FKA
  • 记录.FKB

...这正是我所期望的。问题是,SQLMetal 生成的类会产生以下属性:

  • 记录.FK_AId
  • 记录.FK_BId
  • 记录.FKA
  • 记录.FKBTableNameGoesHere

现在我可以改变生成的类,所以 FKBTableNameGoesHere 将是 FK_B,但是生成的文件经常被不同的团队成员更改,所以这将是一个巨大的痛苦。有一个简单的解决方法吗?

提前致谢。

编辑 2 因此,我认为解决方案是创建一个部分类,该类具有一个名为我想要的属性的属性,并让 getter/setter 指向名称不佳的属性。这适用于选择,但不适用于 where 子句等。有人有解决方案吗??

4

4 回答 4

4

因此,我的解决方案是添加另一个部分类并添加一个属性,其中 get/set 指向奇怪的 FKBTableNameGoesHere 属性。这样我们就不必不断修改生成的类。不能完全解决问题,但应该让开发人员更清楚地了解该属性的含义。有人看到该解决方案有任何潜在问题吗?

编辑- 所以,显然这只适用于选择数据而不是基于它的过滤。不像我希望的那样容易修复。有人有其他建议吗?

编辑 2 - 天哪,认为这会是一个常见的问题,但我想不是。无论如何,事实证明我在正确的轨道上。我找到了这篇文章:

同一张表的多个外键

这给了我一个想法,即我不能直接链接到另一个属性的 getter/setter,因为幕后可能还有很多事情要做。这个家伙的解决方案并不完全是答案,但它让我朝着正确的方向前进。添加关联属性是最终做到的:

public partial class ProblemClass
{
    [Association(Name = "FK__SomeLinkHere", Storage = "_OriginalPoorlyNamedStorageVariable", ThisKey = "FK_1_Id", OtherKey = "Id", IsForeignKey = true)]
    public FKType MyNewBetterName
    {
        get
        {
            return this._OriginalPoorlyNamedStorageVariable.Entity;
        }

        set
        {
            this.OriginalPoorlyNamedStorageVariable = value;
        }
    }
}

将为仍然可以提出更清洁解决方案的任何人开放赏金。

于 2010-09-20T15:31:45.883 回答
0

这个问题很久以前就出现了,但我只是遇到了这个问题。我正在使用 DBML,我通过编辑关系解决了这个问题。如果展开 ParentProperty,则可以通过更改 Name 属性来设置属性名称。

这是来自 DBML 的 XML(成员属性已更改):

  <Association Name="State_StateAction1" Member="DestinationState" ThisKey="DestinationStateId" OtherKey="Id" Type="State" IsForeignKey="true" />
于 2012-07-26T22:07:05.343 回答
0

好的,我会提出一个新的答案(有点晚了,抱歉),即使协会的名称发生变化,它也会起作用。

此方法将查找主实体的关联属性,然后在主表中查找值。设想:

表:通过equalsOrders引用表。所以我们传递了主表的Meta信息,字段(也就是被引用的字段)和字段(就是我们想要的值)。CustomersOrders.CustomerIDCustomers.IdCustomerIDName

/// <summary>
/// Gets the value of "referencedValueFieldName" of an associated table of the "fieldName" in the "mainTable".
/// This is equivalent of doing the next LINQ query:
///   var qryForeignValue = 
///     from mt in modelContext.mainTable
///     join at in modelContext.associatedTable
///       on mt.fieldName equals at.associatedField
///     select new { Value = at.referencedValueField }
/// </summary>
/// <param name="mainTable">Metadata of the table of the fieldName's field</param>
/// <param name="fieldName">Name of the field of the foreign key</param>
/// <param name="referencedValueFieldName">Which field of the foreign table do you the value want</param>
/// <returns>The value of the referenced table</returns>
/// <remarks>This method only works with foreign keys of one field.</remarks>
private Object GetForeignValue(MetaTable mainTable, string fieldName, string referencedValueFieldName) {
  Object resultValue = null;
  foreach (MetaDataMember member in mainTable.RowType.DataMembers) {
    if ((member.IsAssociation) && (member.Association.IsForeignKey)) {
      if (member.Association.ThisKey[0].Name == fieldName) {
        Type associationType = fPointOfSaleData.GetType();
        PropertyInfo associationInfo = associationType.GetProperty(member.Name);
        if (associationInfo == null)
          throw new Exception("Association property not found on member");

        Object associationValue = associationType.InvokeMember(associationInfo.Name, BindingFlags.GetProperty, null, fPointOfSaleData, null);

        if (associationValue != null) {
          Type foreignType = associationValue.GetType();
          PropertyInfo foreignInfo = foreignType.GetProperty(referencedValueFieldName);
          if (foreignInfo == null)
            throw new Exception("Foreign property not found on assiciation member");

          resultValue = foreignType.InvokeMember(foreignInfo.Name, BindingFlags.GetProperty, null, associationValue, null);
        }

        break;
      }
    }
  }
  return resultValue;
}

和电话:

      AttributeMappingSource mapping = new System.Data.Linq.Mapping.AttributeMappingSource();
      MetaModel model = mapping.GetModel(typeof(WhateverClassesDataContext));
      MetaTable table = model.GetTable(typeof(Order));
      Object value = GetForeignValue(table, "CustomerId" /* In the main table */, "Name" /* In the master table */);

问题是它只适用于只有一个引用字段的外键。但是,更改为多个键非常简单。

这是一种获取主表字段值的方法,可以改成返回整个对象。

PS:我觉得我的英语有一些错误,这对我来说是相当困难的。

于 2012-05-22T05:51:43.940 回答
0

这是 Ocelot20 版本的变体:

public partial class ProblemClass
{
    partial void OnCreated()
    {
        this._MyNewBetterName = default(EntityRef<FKType>);
    }
    protected EntityRef<FKType> _MyNewBetterName;

    [Association(Name = "FK__SomeLinkHere", Storage = "_MyNewBetterName", ThisKey = "FK_1_Id", OtherKey = "Id", IsForeignKey = true)]
    public EntityRef<FKType> MyNewBetterName
    {
        get
        {
            return this._MyNewBetterName.Entity;
        }

        set
        {
            this.MyNewBetterName = value;
        }
    }
}

有了这个,您甚至不需要知道原始存储名称,但是我不确定 setter 是否可以工作(我只使用了 getter,但它就像一个魅力)。您甚至可以将此关系定义打包到一个基类中并使部分继承它(如果您需要跨多个模型\上下文重用关系,这应该会更容易),但要注意的是,您必须OnCreated()在每个部分内部定义因为那些不能在 c# 中继承(见这个)。

于 2014-10-13T10:41:15.890 回答